diff options
44 files changed, 905 insertions, 329 deletions
diff --git a/src/doc/reference.md b/src/doc/reference.md index c19aec78de2..5be61a51bf0 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -638,7 +638,7 @@ apply to the crate as a whole. ``` A crate that contains a `main` function can be compiled to an executable. If a -`main` function is present, its return type must be [`unit`](#primitive-types) +`main` function is present, its return type must be [`unit`](#tuple-types) and it must take no arguments. # Items and attributes @@ -928,21 +928,20 @@ A _generic function_ allows one or more _parameterized types_ to appear in its signature. Each type parameter must be explicitly declared, in an angle-bracket-enclosed, comma-separated list following the function name. -```{.ignore} -fn iter<T, F>(seq: &[T], f: F) where T: Copy, F: Fn(T) { - for elt in seq { f(*elt); } -} -fn map<T, U, F>(seq: &[T], f: F) -> Vec<U> where T: Copy, U: Copy, F: Fn(T) -> U { - let mut acc = vec![]; - for elt in seq { acc.push(f(*elt)); } - acc -} +```rust,ignore +// foo is generic over A and B + +fn foo<A, B>(x: A, y: B) { ``` Inside the function signature and body, the name of the type parameter can be used as a type name. [Trait](#traits) bounds can be specified for type parameters to allow methods with that trait to be called on values of that type. This is -specified using the `where` syntax, as in the above example. +specified using the `where` syntax: + +```rust,ignore +fn foo<T>(x: T) where T: Debug { +``` When a generic function is referenced, its type is instantiated based on the context of the reference. For example, calling the `iter` function defined @@ -2874,7 +2873,7 @@ The `+`, `-`, `*`, `/`, `%`, `&`, `|`, `^`, `<<`, and `>>` operators may be composed with the `=` operator. The expression `lval OP= val` is equivalent to `lval = lval OP val`. For example, `x = x + 1` may be written as `x += 1`. -Any such expression always has the [`unit`](#primitive-types) type. +Any such expression always has the [`unit`](#tuple-types) type. #### Operator precedence @@ -3316,6 +3315,9 @@ assert!(b != "world"); assert!(p.0 == 10); ``` +For historical reasons and convenience, the tuple type with no elements (`()`) +is often called ‘unit’ or ‘the unit type’. + ### Array, and Slice types Rust has two different types for a list of items: diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index 428897821cf..ce52ea5d690 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -120,7 +120,7 @@ let y = &mut num; ``` If your closure requires it, however, Rust will take ownership and move -the environment instead: +the environment instead. This doesn’t work: ```rust,ignore let nums = vec![1, 2, 3]; @@ -130,7 +130,7 @@ let takes_nums = || nums; println!("{:?}", nums); ``` -This gives us: +We get this error: ```text note: `nums` moved into closure environment here because it has type diff --git a/src/doc/trpl/rust-inside-other-languages.md b/src/doc/trpl/rust-inside-other-languages.md index 0a1860769d2..6129c98259b 100644 --- a/src/doc/trpl/rust-inside-other-languages.md +++ b/src/doc/trpl/rust-inside-other-languages.md @@ -66,10 +66,14 @@ threads = [] 5_000_000.times do count += 1 end + + count end end -threads.each { |t| t.join } +threads.each do |t| + puts "Thread finished with count=#{t.value}" +end puts "done!" ``` @@ -103,50 +107,26 @@ use std::thread; fn process() { let handles: Vec<_> = (0..10).map(|_| { thread::spawn(|| { - let mut _x = 0; + let mut x = 0; for _ in (0..5_000_000) { - _x += 1 + x += 1 } + x }) }).collect(); for h in handles { - h.join().ok().expect("Could not join a thread!"); + println!("Thread finished with count={}", + h.join().map_err(|_| "Could not join a thread!").unwrap()); } + println!("done!"); } ``` Some of this should look familiar from previous examples. We spin up ten threads, collecting them into a `handles` vector. Inside of each thread, we -loop five million times, and add one to `_x` each time. Why the underscore? -Well, if we remove it and compile: - -```bash -$ cargo build - Compiling embed v0.1.0 (file:///home/steve/src/embed) -src/lib.rs:3:1: 16:2 warning: function is never used: `process`, #[warn(dead_code)] on by default -src/lib.rs:3 fn process() { -src/lib.rs:4 let handles: Vec<_> = (0..10).map(|_| { -src/lib.rs:5 thread::spawn(|| { -src/lib.rs:6 let mut x = 0; -src/lib.rs:7 for _ in (0..5_000_000) { -src/lib.rs:8 x += 1 - ... -src/lib.rs:6:17: 6:22 warning: variable `x` is assigned to, but never used, #[warn(unused_variables)] on by default -src/lib.rs:6 let mut x = 0; - ^~~~~ -``` - -That first warning is because we are building a library. If we had a test -for this function, the warning would go away. But for now, it’s never -called. - -The second is related to `x` versus `_x`. Because we never actually _do_ -anything with `x`, we get a warning about it. In our case, that’s perfectly -okay, as we’re just trying to waste CPU cycles. Prefixing `x` with the -underscore removes the warning. - -Finally, we join on each thread. +loop five million times, and add one to `x` each time. Finally, we join on +each thread. Right now, however, this is a Rust library, and it doesn’t expose anything that’s callable from C. If we tried to hook this up to another language right diff --git a/src/doc/trpl/trait-objects.md b/src/doc/trpl/trait-objects.md index 3da29c9b817..f9dbc143c82 100644 --- a/src/doc/trpl/trait-objects.md +++ b/src/doc/trpl/trait-objects.md @@ -300,7 +300,3 @@ let y = TraitObject { // y.method(); (y.vtable.method)(y.data); ``` - -If `b` or `y` were owning trait objects (`Box<Foo>`), there would be a -`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of -scope. diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 741452b75f1..ba41f438b37 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1469,42 +1469,26 @@ impl<T> ops::DerefMut for Vec<T> { impl<T> FromIterator<T> for Vec<T> { #[inline] fn from_iter<I: IntoIterator<Item=T>>(iterable: I) -> Vec<T> { + // Unroll the first iteration, as the vector is going to be + // expanded on this iteration in every case when the iterable is not + // empty, but the loop in extend_desugared() is not going to see the + // vector being full in the few subsequent loop iterations. + // So we get better branch prediction and the possibility to + // construct the vector with initial estimated capacity. let mut iterator = iterable.into_iter(); - let (lower, _) = iterator.size_hint(); - let mut vector = Vec::with_capacity(lower); - - // This function should be the moral equivalent of: - // - // for item in iterator { - // vector.push(item); - // } - // - // This equivalent crucially runs the iterator precisely once. Below we - // actually in theory run the iterator twice (one without bounds checks - // and one with). To achieve the "moral equivalent", we use the `if` - // statement below to break out early. - // - // If the first loop has terminated, then we have one of two conditions. - // - // 1. The underlying iterator returned `None`. In this case we are - // guaranteed that less than `vector.capacity()` elements have been - // returned, so we break out early. - // 2. The underlying iterator yielded `vector.capacity()` elements and - // has not yielded `None` yet. In this case we run the iterator to - // its end below. - for element in iterator.by_ref().take(vector.capacity()) { - let len = vector.len(); - unsafe { - ptr::write(vector.get_unchecked_mut(len), element); - vector.set_len(len + 1); - } - } - - if vector.len() == vector.capacity() { - for element in iterator { - vector.push(element); + let mut vector = match iterator.next() { + None => return Vec::new(), + Some(element) => { + let (lower, _) = iterator.size_hint(); + let mut vector = Vec::with_capacity(1 + lower); + unsafe { + ptr::write(vector.get_unchecked_mut(0), element); + vector.set_len(1); + } + vector } - } + }; + vector.extend_desugared(iterator); vector } } @@ -1569,11 +1553,27 @@ impl<'a, T> IntoIterator for &'a mut Vec<T> { impl<T> Extend<T> for Vec<T> { #[inline] fn extend<I: IntoIterator<Item=T>>(&mut self, iterable: I) { - let iterator = iterable.into_iter(); - let (lower, _) = iterator.size_hint(); - self.reserve(lower); - for element in iterator { - self.push(element) + self.extend_desugared(iterable.into_iter()) + } +} + +impl<T> Vec<T> { + fn extend_desugared<I: Iterator<Item=T>>(&mut self, mut iterator: I) { + // This function should be the moral equivalent of: + // + // for item in iterator { + // self.push(item); + // } + while let Some(element) = iterator.next() { + let len = self.len(); + if len == self.capacity() { + let (lower, _) = iterator.size_hint(); + self.reserve(lower + 1); + } + unsafe { + ptr::write(self.get_unchecked_mut(len), element); + self.set_len(len + 1); + } } } } diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 9938c299615..df371752b86 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -74,17 +74,8 @@ pub const MAX: char = '\u{10ffff}'; /// ``` /// use std::char; /// -/// let c = char::from_u32(10084); // produces `Some(❤)` -/// assert_eq!(c, Some('❤')); -/// ``` -/// -/// An invalid character: -/// -/// ``` -/// use std::char; -/// -/// let none = char::from_u32(1114112); -/// assert_eq!(none, None); +/// assert_eq!(char::from_u32(0x2764), Some('❤')); +/// assert_eq!(char::from_u32(0x110000), None); // invalid character /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4db64a3097e..ef8b371f061 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -638,10 +638,10 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method `.split()`. + #[doc="Created with the method `.split()`."] struct Split; reverse: - /// Created with the method `.rsplit()`. + #[doc="Created with the method `.rsplit()`."] struct RSplit; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -652,10 +652,10 @@ generate_pattern_iterators! { generate_pattern_iterators! { forward: - /// Created with the method `.split_terminator()`. + #[doc="Created with the method `.split_terminator()`."] struct SplitTerminator; reverse: - /// Created with the method `.rsplit_terminator()`. + #[doc="Created with the method `.rsplit_terminator()`."] struct RSplitTerminator; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -698,10 +698,10 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method `.splitn()`. + #[doc="Created with the method `.splitn()`."] struct SplitN; reverse: - /// Created with the method `.rsplitn()`. + #[doc="Created with the method `.rsplitn()`."] struct RSplitN; stability: #[stable(feature = "rust1", since = "1.0.0")] @@ -732,10 +732,10 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method `.match_indices()`. + #[doc="Created with the method `.match_indices()`."] struct MatchIndices; reverse: - /// Created with the method `.rmatch_indices()`. + #[doc="Created with the method `.rmatch_indices()`."] struct RMatchIndices; stability: #[unstable(feature = "core", @@ -773,10 +773,10 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: - /// Created with the method `.matches()`. + #[doc="Created with the method `.matches()`."] struct Matches; reverse: - /// Created with the method `.rmatches()`. + #[doc="Created with the method `.rmatches()`."] struct RMatches; stability: #[unstable(feature = "core", reason = "type got recently added")] diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index b7a40a3f9cf..2676d4879b5 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -146,7 +146,10 @@ pub use funcs::bsd43::*; #[link(name = "m")] extern {} -#[cfg(all(target_env = "musl", not(test)))] +// When compiling rust with musl, statically include libc.a in liblibc.rlib. +// A cargo build of the libc crate will therefore automatically pick up the +// libc.a symbols because liblibc is transitively linked to by the stdlib. +#[cfg(all(target_env = "musl", not(feature = "cargo-build"), not(test)))] #[link(name = "c", kind = "static")] extern {} diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 5068836b557..e618aa5a5b7 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -48,6 +48,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> { struct_has_extern_repr: bool, ignore_non_const_paths: bool, inherited_pub_visibility: bool, + ignore_variant_stack: Vec<ast::NodeId>, } impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { @@ -60,6 +61,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { struct_has_extern_repr: false, ignore_non_const_paths: false, inherited_pub_visibility: false, + ignore_variant_stack: vec![], } } @@ -80,7 +82,9 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { def::DefPrimTy(_) => (), def::DefVariant(enum_id, variant_id, _) => { self.check_def_id(enum_id); - self.check_def_id(variant_id); + if !self.ignore_variant_stack.contains(&variant_id.node) { + self.check_def_id(variant_id); + } } _ => { self.check_def_id(def.def_id()); @@ -272,6 +276,23 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { visit::walk_expr(self, expr); } + fn visit_arm(&mut self, arm: &ast::Arm) { + if arm.pats.len() == 1 { + let pat = &*arm.pats[0]; + let variants = pat_util::necessary_variants(&self.tcx.def_map, pat); + + // Inside the body, ignore constructions of variants + // necessary for the pattern to match. Those construction sites + // can't be reached unless the variant is constructed elsewhere. + let len = self.ignore_variant_stack.len(); + self.ignore_variant_stack.push_all(&*variants); + visit::walk_arm(self, arm); + self.ignore_variant_stack.truncate(len); + } else { + visit::walk_arm(self, arm); + } + } + fn visit_pat(&mut self, pat: &ast::Pat) { let def_map = &self.tcx.def_map; match pat.node { @@ -393,6 +414,11 @@ fn create_and_seed_worklist(tcx: &ty::ctxt, worklist.push(*id); } for id in reachable_symbols { + // Reachable variants can be dead, because we warn about + // variants never constructed, not variants never used. + if let Some(ast_map::NodeVariant(..)) = tcx.map.find(*id) { + continue; + } worklist.push(*id); } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index bb4c702f373..0cb302d79b8 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -201,3 +201,27 @@ pub fn def_to_path(tcx: &ty::ctxt, id: ast::DefId) -> ast::Path { span: DUMMY_SP, }) } + +/// Return variants that are necessary to exist for the pattern to match. +pub fn necessary_variants(dm: &DefMap, pat: &ast::Pat) -> Vec<ast::NodeId> { + let mut variants = vec![]; + walk_pat(pat, |p| { + match p.node { + ast::PatEnum(_, _) | + ast::PatIdent(_, _, None) | + ast::PatStruct(..) => { + match dm.borrow().get(&p.id) { + Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => { + variants.push(id.node); + } + _ => () + } + } + _ => () + } + true + }); + variants.sort(); + variants.dedup(); + variants +} diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 1631a33588c..4ef8f380e82 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -389,15 +389,19 @@ fn opt_normalize_projection_type<'a,'b,'tcx>( } } Ok(ProjectedTy::NoProgress(projected_ty)) => { + debug!("normalize_projection_type: projected_ty={} no progress", + projected_ty.repr(selcx.tcx())); Some(Normalized { value: projected_ty, obligations: vec!() }) } Err(ProjectionTyError::TooManyCandidates) => { + debug!("normalize_projection_type: too many candidates"); None } Err(ProjectionTyError::TraitSelectionError(_)) => { + debug!("normalize_projection_type: ERROR"); // if we got an error processing the `T as Trait` part, // just return `ty::err` but add the obligation `T : // Trait`, which when processed will cause the error to be diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index 9ed827da8b2..efbd4c3ef5e 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -482,6 +482,7 @@ pub struct Sha256 { impl Sha256 { /// Construct a new instance of a SHA-256 digest. + /// Do not – under any circumstances – use this where timing attacks might be possible! pub fn new() -> Sha256 { Sha256 { engine: Engine256::new(&H256) diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 4d7f00e9523..bf331705b32 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -976,6 +976,9 @@ extern { pub fn LLVMAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t); pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t); pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); + pub fn LLVMAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint, + Name: *const c_char, + Value: *const c_char); pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong; pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong); @@ -1920,6 +1923,7 @@ extern { VarInfo: DIVariable, AddrOps: *const i64, AddrOpsCount: c_uint, + DL: ValueRef, InsertAtEnd: BasicBlockRef) -> ValueRef; @@ -1928,6 +1932,7 @@ extern { VarInfo: DIVariable, AddrOps: *const i64, AddrOpsCount: c_uint, + DL: ValueRef, InsertBefore: ValueRef) -> ValueRef; @@ -2035,7 +2040,6 @@ extern { Level: CodeGenOptLevel, EnableSegstk: bool, UseSoftFP: bool, - NoFramePointerElim: bool, PositionIndependentExecutable: bool, FunctionSections: bool, DataSections: bool) -> TargetMachineRef; @@ -2046,6 +2050,11 @@ extern { pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, M: ModuleRef, DisableSimplifyLibCalls: bool); + pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef, + OptLevel: CodeGenOptLevel, + MergeFunctions: bool, + SLPVectorize: bool, + LoopVectorize: bool); pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, DisableSimplifyLibCalls: bool); pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); @@ -2116,6 +2125,12 @@ extern { pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef); } +// LLVM requires symbols from this library, but apparently they're not printed +// during llvm-config? +#[cfg(windows)] +#[link(name = "ole32")] +extern {} + pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) { unsafe { LLVMSetInstructionCallConv(instr, cc as c_uint); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 5352c61d8c0..1b8f049972f 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -10,7 +10,7 @@ use back::lto; use back::link::{get_cc_prog, remove}; -use session::config::{OutputFilenames, NoDebugInfo, Passes, SomePasses, AllPasses}; +use session::config::{OutputFilenames, Passes, SomePasses, AllPasses}; use session::Session; use session::config; use llvm; @@ -188,10 +188,6 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { let opt_level = get_llvm_opt_level(sess.opts.optimize); let use_softfp = sess.opts.cg.soft_float; - // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter. - let no_fp_elim = (sess.opts.debuginfo != NoDebugInfo) || - !sess.target.target.options.eliminate_frame_pointer; - let any_library = sess.crate_types.borrow().iter().any(|ty| { *ty != config::CrateTypeExecutable }); @@ -237,7 +233,6 @@ fn create_target_machine(sess: &Session) -> TargetMachineRef { opt_level, true /* EnableSegstk */, use_softfp, - no_fp_elim, !any_library && reloc_model == llvm::RelocPIC, ffunction_sections, fdata_sections, @@ -279,6 +274,9 @@ struct ModuleConfig { no_prepopulate_passes: bool, no_builtins: bool, time_passes: bool, + vectorize_loop: bool, + vectorize_slp: bool, + merge_functions: bool, } unsafe impl Send for ModuleConfig { } @@ -301,6 +299,9 @@ impl ModuleConfig { no_prepopulate_passes: false, no_builtins: false, time_passes: false, + vectorize_loop: false, + vectorize_slp: false, + merge_functions: false, } } @@ -309,6 +310,18 @@ impl ModuleConfig { self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; self.no_builtins = trans.no_builtins; self.time_passes = sess.time_passes(); + + // Copy what clang does by turning on loop vectorization at O2 and + // slp vectorization at O3. Otherwise configure other optimization aspects + // of this pass manager builder. + self.vectorize_loop = !sess.opts.cg.no_vectorize_loops && + (sess.opts.optimize == config::Default || + sess.opts.optimize == config::Aggressive); + self.vectorize_slp = !sess.opts.cg.no_vectorize_slp && + sess.opts.optimize == config::Aggressive; + + self.merge_functions = sess.opts.optimize == config::Default || + sess.opts.optimize == config::Aggressive; } } @@ -448,27 +461,26 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let pass = CString::new(pass).unwrap(); llvm::LLVMRustAddPass(fpm, pass.as_ptr()) }; - if !config.no_verify { assert!(addpass("verify")); } + if !config.no_verify { assert!(addpass("verify")); } if !config.no_prepopulate_passes { llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); - populate_llvm_passes(fpm, mpm, llmod, opt_level, - config.no_builtins); + populate_llvm_passes(fpm, mpm, llmod, opt_level, &config); } for pass in &config.passes { - let pass = CString::new(pass.clone()).unwrap(); - if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { - cgcx.handler.warn(&format!("unknown pass {:?}, ignoring", pass)); + if !addpass(pass) { + cgcx.handler.warn(&format!("unknown pass `{}`, ignoring", + pass)); } } for pass in &cgcx.plugin_passes { - let pass = CString::new(pass.clone()).unwrap(); - if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) { - cgcx.handler.err(&format!("a plugin asked for LLVM pass {:?} but LLVM \ - does not recognize it", pass)); + if !addpass(pass) { + cgcx.handler.err(&format!("a plugin asked for LLVM pass \ + `{}` but LLVM does not \ + recognize it", pass)); } } @@ -520,7 +532,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); f(cpm); - llvm::LLVMDisposePassManager(cpm); } if config.emit_bc { @@ -537,13 +548,15 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let out = path2cstr(&out); with_codegen(tm, llmod, config.no_builtins, |cpm| { llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr()); + llvm::LLVMDisposePassManager(cpm); }) } if config.emit_asm { let path = output_names.with_extension(&format!("{}.s", name_extra)); with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::AssemblyFileType); + write_output_file(cgcx.handler, tm, cpm, llmod, &path, + llvm::AssemblyFileType); }); } @@ -1008,16 +1021,9 @@ unsafe fn configure_llvm(sess: &Session) { use std::sync::Once; static INIT: Once = Once::new(); - // Copy what clang does by turning on loop vectorization at O2 and - // slp vectorization at O3 - let vectorize_loop = !sess.opts.cg.no_vectorize_loops && - (sess.opts.optimize == config::Default || - sess.opts.optimize == config::Aggressive); - let vectorize_slp = !sess.opts.cg.no_vectorize_slp && - sess.opts.optimize == config::Aggressive; - let mut llvm_c_strs = Vec::new(); let mut llvm_args = Vec::new(); + { let mut add = |arg: &str| { let s = CString::new(arg).unwrap(); @@ -1025,8 +1031,6 @@ unsafe fn configure_llvm(sess: &Session) { llvm_c_strs.push(s); }; add("rustc"); // fake program name - if vectorize_loop { add("-vectorize-loops"); } - if vectorize_slp { add("-vectorize-slp"); } if sess.time_llvm_passes() { add("-time-passes"); } if sess.print_llvm_passes() { add("-debug-pass=Structure"); } @@ -1084,41 +1088,40 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef, mpm: llvm::PassManagerRef, llmod: ModuleRef, opt: llvm::CodeGenOptLevel, - no_builtins: bool) { + config: &ModuleConfig) { // Create the PassManagerBuilder for LLVM. We configure it with // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); + + llvm::LLVMRustConfigurePassManagerBuilder(builder, opt, + config.merge_functions, + config.vectorize_slp, + config.vectorize_loop); + + llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins); + + // Here we match what clang does (kinda). For O0 we only inline + // always-inline functions (but don't add lifetime intrinsics), at O1 we + // inline with lifetime intrinsics, and O2+ we add an inliner with a + // thresholds copied from clang. match opt { llvm::CodeGenLevelNone => { - // Don't add lifetime intrinsics at O0 llvm::LLVMRustAddAlwaysInlinePass(builder, false); } llvm::CodeGenLevelLess => { llvm::LLVMRustAddAlwaysInlinePass(builder, true); } - // numeric values copied from clang llvm::CodeGenLevelDefault => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, - 225); + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); } llvm::CodeGenLevelAggressive => { - llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, - 275); + llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275); } } - llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint); - llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins); // Use the builder to populate the function/module pass managers. llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm); llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm); llvm::LLVMPassManagerBuilderDispose(builder); - - match opt { - llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => { - llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _); - } - _ => {} - }; } diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index d9e1a75d3dc..68d72ab4241 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -1029,11 +1029,26 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } General(ity, ref cases, _) => { let ccx = bcx.ccx(); - let unr_cx = fcx.new_temp_block("enum-variant-iter-unr"); - Unreachable(unr_cx); + + // See the comments in trans/base.rs for more information (inside + // iter_structural_ty), but the gist here is that if the enum's + // discriminant is *not* in the range that we're expecting (in which + // case we'll take the fall-through branch on the switch + // instruction) then we can't just optimize this to an Unreachable + // block. + // + // Currently we still have filling drop, so this means that the drop + // glue for enums may be called when the enum has been paved over + // with the "I've been dropped" value. In this case the default + // branch of the switch instruction will actually be taken at + // runtime, so the basic block isn't actually unreachable, so we + // need to make it do something with defined behavior. In this case + // we just return early from the function. + let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); let discr_val = trans_get_discr(bcx, r, value, None); - let llswitch = Switch(bcx, discr_val, unr_cx.llbb, cases.len()); + let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len()); let bcx_next = fcx.new_temp_block("enum-variant-iter-next"); for (discr, case) in cases.iter().enumerate() { diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index d4ce17cc7b5..b0f44e65739 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -12,6 +12,7 @@ use libc::{c_uint, c_ulonglong}; use llvm::{self, ValueRef, AttrHelper}; use middle::ty::{self, ClosureTyper}; +use session::config::NoDebugInfo; use syntax::abi; use syntax::ast; pub use syntax::attr::InlineAttr; @@ -106,6 +107,20 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe use syntax::attr::*; inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); + // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a + // parameter. + let no_fp_elim = (ccx.sess().opts.debuginfo != NoDebugInfo) || + !ccx.sess().target.target.options.eliminate_frame_pointer; + if no_fp_elim { + unsafe { + let attr = "no-frame-pointer-elim\0".as_ptr() as *const _; + let val = "true\0".as_ptr() as *const _; + llvm::LLVMAddFunctionAttrStringValue(llfn, + llvm::FunctionIndex as c_uint, + attr, val); + } + } + for attr in attrs { if attr.check_name("no_stack_check") { split_stack(llfn, false); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 0ec2d1abb09..c2293dcc6d4 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -481,9 +481,23 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } (_match::Switch, Some(lldiscrim_a)) => { cx = f(cx, lldiscrim_a, cx.tcx().types.isize); - let unr_cx = fcx.new_temp_block("enum-iter-unr"); - Unreachable(unr_cx); - let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, + + // Create a fall-through basic block for the "else" case of + // the switch instruction we're about to generate. Note that + // we do **not** use an Unreachable instruction here, even + // though most of the time this basic block will never be hit. + // + // When an enum is dropped it's contents are currently + // overwritten to DTOR_DONE, which means the discriminant + // could have changed value to something not within the actual + // range of the discriminant. Currently this function is only + // used for drop glue so in this case we just return quickly + // from the outer function, and any other use case will only + // call this for an already-valid enum in which case the `ret + // void` will never be hit. + let ret_void_cx = fcx.new_temp_block("enum-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); + let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); let next_cx = fcx.new_temp_block("enum-iter-next"); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index d23543924dd..9133004dfef 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -954,8 +954,15 @@ impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> { } } + /// Manipulate cleanup scope for call arguments. Conceptually, each + /// argument to a call is an lvalue, and performing the call moves each + /// of the arguments into a new rvalue (which gets cleaned up by the + /// callee). As an optimization, instead of actually performing all of + /// those moves, trans just manipulates the cleanup scope to obtain the + /// same effect. pub fn drop_non_lifetime_clean(&mut self) { self.cleanups.retain(|c| c.is_lifetime_end()); + self.clear_cached_exits(); } } diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 42aa96ed21e..5e35e5c67f3 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1677,7 +1677,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, DIB(cx), containing_scope, enum_name.as_ptr(), - UNKNOWN_FILE_METADATA, + file_metadata, UNKNOWN_LINE_NUMBER, bytes_to_bits(enum_type_size), bytes_to_bits(enum_type_align), diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 7210c35e0e0..06f1a56c6ef 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -485,10 +485,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let param_metadata = unsafe { llvm::LLVMDIBuilderCreateTemplateTypeParameter( DIB(cx), - file_metadata, + ptr::null_mut(), name.as_ptr(), actual_self_type_metadata, - ptr::null_mut(), + file_metadata, 0, 0) }; @@ -519,10 +519,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let param_metadata = unsafe { llvm::LLVMDIBuilderCreateTemplateTypeParameter( DIB(cx), - file_metadata, + ptr::null_mut(), name.as_ptr(), actual_type_metadata, - ptr::null_mut(), + file_metadata, 0, 0) }; @@ -581,12 +581,14 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, loc.line, loc.col.to_usize())); unsafe { + let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder()); let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd( DIB(cx), alloca, metadata, address_operations.as_ptr(), address_operations.len() as c_uint, + debug_loc, bcx.llbb); llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr); diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 6e306047f75..9fefd7ac036 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -99,7 +99,6 @@ enum CastError { NeedViaInt, NeedViaUsize, NonScalar, - RefToMutPtr } impl<'tcx> CastCheck<'tcx> { @@ -161,11 +160,6 @@ impl<'tcx> CastCheck<'tcx> { fcx.infcx().ty_to_string(self.cast_ty)) }, self.expr_ty, None); } - CastError::RefToMutPtr => { - span_err!(fcx.tcx().sess, self.span, E0188, - "cannot cast an immutable reference to a \ - mutable pointer"); - } } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 79449b2f10d..915aadd722b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -59,10 +59,12 @@ struct Candidate<'tcx> { } enum CandidateKind<'tcx> { - InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>), + InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>, + /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>), ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize), ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>, - subst::Substs<'tcx>, ItemIndex), + subst::Substs<'tcx>, ItemIndex, + /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>), ClosureCandidate(/* Trait */ ast::DefId, ItemIndex), WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex), ProjectionCandidate(ast::DefId, ItemIndex), @@ -398,16 +400,24 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id); - let impl_ty = self.fcx.instantiate_type_scheme(self.span, &impl_substs, &impl_ty); + let impl_ty = impl_ty.subst(self.tcx(), &impl_substs); // Determine the receiver type that the method itself expects. - let xform_self_ty = - self.xform_self_ty(&item, impl_ty, &impl_substs); + let xform_self_ty = self.xform_self_ty(&item, impl_ty, &impl_substs); + + // We can't use normalize_associated_types_in as it will pollute the + // fcx's fulfillment context after this probe is over. + let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, cause, &xform_self_ty); + debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}", + xform_self_ty.repr(self.tcx())); self.inherent_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item, - kind: InherentImplCandidate(impl_def_id, impl_substs) + kind: InherentImplCandidate(impl_def_id, impl_substs, obligations) }); } @@ -653,12 +663,24 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { impl_trait_ref.self_ty(), impl_trait_ref.substs); + // Normalize the receiver. We can't use normalize_associated_types_in + // as it will pollute the fcx's fulfillment context after this probe + // is over. + let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); + let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx); + let traits::Normalized { value: xform_self_ty, obligations } = + traits::normalize(selcx, cause, &xform_self_ty); + debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx())); self.extension_candidates.push(Candidate { xform_self_ty: xform_self_ty, item: item.clone(), - kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index) + kind: ExtensionImplCandidate(impl_def_id, + impl_trait_ref, + impl_substs, + item_index, + obligations) }); }); } @@ -1026,8 +1048,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // match as well (or at least may match, sometimes we // don't have enough information to fully evaluate). match probe.kind { - InherentImplCandidate(impl_def_id, ref substs) | - ExtensionImplCandidate(impl_def_id, _, ref substs, _) => { + InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) | + ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => { let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx); let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); @@ -1046,8 +1068,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { debug!("impl_obligations={}", obligations.repr(self.tcx())); // Evaluate those obligations to see if they might possibly hold. - obligations.iter().all(|o| selcx.evaluate_obligation(o)) && - norm_obligations.iter().all(|o| selcx.evaluate_obligation(o)) + obligations.iter() + .chain(norm_obligations.iter()).chain(ref_obligations.iter()) + .all(|o| selcx.evaluate_obligation(o)) + } ProjectionCandidate(..) | @@ -1281,13 +1305,13 @@ impl<'tcx> Candidate<'tcx> { Pick { item: self.item.clone(), kind: match self.kind { - InherentImplCandidate(def_id, _) => { + InherentImplCandidate(def_id, _, _) => { InherentImplPick(def_id) } ObjectCandidate(def_id, item_num, real_index) => { ObjectPick(def_id, item_num, real_index) } - ExtensionImplCandidate(def_id, _, _, index) => { + ExtensionImplCandidate(def_id, _, _, index, _) => { ExtensionImplPick(def_id, index) } ClosureCandidate(trait_def_id, index) => { @@ -1315,9 +1339,9 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { - InherentImplCandidate(def_id, _) => ImplSource(def_id), + InherentImplCandidate(def_id, _, _) => ImplSource(def_id), ObjectCandidate(def_id, _, _) => TraitSource(def_id), - ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id), + ExtensionImplCandidate(def_id, _, _, _, _) => ImplSource(def_id), ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id), WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()), ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id), @@ -1335,7 +1359,7 @@ impl<'tcx> Candidate<'tcx> { ClosureCandidate(trait_def_id, item_num) => { Some((trait_def_id, item_num)) } - ExtensionImplCandidate(_, ref trait_ref, _, item_num) => { + ExtensionImplCandidate(_, ref trait_ref, _, item_num, _) => { Some((trait_ref.def_id, item_num)) } WhereClauseCandidate(ref trait_ref, item_num) => { @@ -1359,13 +1383,14 @@ impl<'tcx> Repr<'tcx> for Candidate<'tcx> { impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { - InherentImplCandidate(ref a, ref b) => - format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)), + InherentImplCandidate(ref a, ref b, ref c) => + format!("InherentImplCandidate({},{},{})", a.repr(tcx), b.repr(tcx), + c.repr(tcx)), ObjectCandidate(a, b, c) => format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c), - ExtensionImplCandidate(ref a, ref b, ref c, ref d) => - format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx), - c.repr(tcx), d), + ExtensionImplCandidate(ref a, ref b, ref c, ref d, ref e) => + format!("ExtensionImplCandidate({},{},{},{},{})", a.repr(tcx), b.repr(tcx), + c.repr(tcx), d, e.repr(tcx)), ClosureCandidate(ref a, ref b) => format!("ClosureCandidate({},{})", a.repr(tcx), b), WhereClauseCandidate(ref a, ref b) => diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 09539931c34..b1580a74876 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -19,10 +19,21 @@ pub enum Parameter { Region(ty::EarlyBoundRegion), } +/// Returns the list of parameters that are constrained by the type `ty` +/// - i.e. the value of each parameter in the list is uniquely determined +/// by `ty` (see RFC 447). pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> { - ty.walk() - .flat_map(|ty| parameters_for_type_shallow(ty)) - .collect() + let mut result = vec![]; + ty::maybe_walk_ty(ty, |t| { + if let ty::TyProjection(..) = t.sty { + false // projections are not injective. + } else { + result.append(&mut parameters_for_type_shallow(t)); + // non-projection type constructors are injective. + true + } + }); + result } pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>) -> Vec<Parameter> { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c23cfd298aa..0080b5e5f22 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -456,13 +456,15 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> { let did = ast_util::local_def(pid); match paths.get(&did) { Some(&(ref fqp, _)) => { + // Needed to determine `self` type. + let parent_basename = Some(fqp[fqp.len() - 1].clone()); search_index.push(IndexItem { ty: shortty(item), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].connect("::"), desc: shorter(item.doc_value()), parent: Some(did), - search_type: None, + search_type: get_index_search_type(&item, parent_basename), }); }, None => {} diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index f090d3e77dd..153b0436087 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -217,6 +217,7 @@ pub use self::local::{LocalKey, LocalKeyState}; pub use self::scoped_tls::ScopedKey; #[doc(hidden)] pub use self::local::__KeyInner as __LocalKeyInner; +#[doc(hidden)] pub use self::scoped_tls::__KeyInner as __ScopedKeyInner; //////////////////////////////////////////////////////////////////////////////// // Builder diff --git a/src/libstd/thread/scoped_tls.rs b/src/libstd/thread/scoped_tls.rs index f0a4c318d91..679902ec7ab 100644 --- a/src/libstd/thread/scoped_tls.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -43,6 +43,9 @@ use prelude::v1::*; +#[doc(hidden)] +pub use self::imp::KeyInner as __KeyInner; + /// Type representing a thread local storage key corresponding to a reference /// to the type parameter `T`. /// @@ -53,7 +56,7 @@ use prelude::v1::*; #[unstable(feature = "scoped_tls", reason = "scoped TLS has yet to have wide enough use to fully consider \ stabilizing its interface")] -pub struct ScopedKey<T> { inner: imp::KeyInner<T> } +pub struct ScopedKey<T> { inner: fn() -> &'static imp::KeyInner<T> } /// Declare a new scoped thread local storage key. /// @@ -64,42 +67,51 @@ pub struct ScopedKey<T> { inner: imp::KeyInner<T> } /// information. #[macro_export] #[allow_internal_unstable] -#[cfg(not(no_elf_tls))] macro_rules! scoped_thread_local { (static $name:ident: $t:ty) => ( - #[cfg_attr(not(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64")), - thread_local)] static $name: ::std::thread::ScopedKey<$t> = - ::std::thread::ScopedKey::new(); + __scoped_thread_local_inner!($t); ); (pub static $name:ident: $t:ty) => ( - #[cfg_attr(not(any(windows, - target_os = "android", - target_os = "ios", - target_os = "openbsd", - target_arch = "aarch64")), - thread_local)] pub static $name: ::std::thread::ScopedKey<$t> = - ::std::thread::ScopedKey::new(); + __scoped_thread_local_inner!($t); ); } +#[doc(hidden)] +#[unstable(feature = "thread_local_internals", + reason = "should not be necessary")] #[macro_export] #[allow_internal_unstable] #[cfg(no_elf_tls)] -macro_rules! scoped_thread_local { - (static $name:ident: $t:ty) => ( - static $name: ::std::thread::ScopedKey<$t> = - ::std::thread::ScopedKey::new(); - ); - (pub static $name:ident: $t:ty) => ( - pub static $name: ::std::thread::ScopedKey<$t> = - ::std::thread::ScopedKey::new(); - ); +macro_rules! __scoped_thread_local_inner { + ($t:ty) => {{ + static _KEY: ::std::thread::__ScopedKeyInner<$t> = + ::std::thread::__ScopedKeyInner::new(); + fn _getit() -> &'static ::std::thread::__ScopedKeyInner<$t> { &_KEY } + ::std::thread::ScopedKey::new(_getit) + }} +} + +#[doc(hidden)] +#[unstable(feature = "thread_local_internals", + reason = "should not be necessary")] +#[macro_export] +#[allow_internal_unstable] +#[cfg(not(no_elf_tls))] +macro_rules! __scoped_thread_local_inner { + ($t:ty) => {{ + #[cfg_attr(not(any(windows, + target_os = "android", + target_os = "ios", + target_os = "openbsd", + target_arch = "aarch64")), + thread_local)] + static _KEY: ::std::thread::__ScopedKeyInner<$t> = + ::std::thread::__ScopedKeyInner::new(); + fn _getit() -> &'static ::std::thread::__ScopedKeyInner<$t> { &_KEY } + ::std::thread::ScopedKey::new(_getit) + }} } #[unstable(feature = "scoped_tls", @@ -107,8 +119,8 @@ macro_rules! scoped_thread_local { stabilizing its interface")] impl<T> ScopedKey<T> { #[doc(hidden)] - pub const fn new() -> ScopedKey<T> { - ScopedKey { inner: imp::KeyInner::new() } + pub const fn new(inner: fn() -> &'static imp::KeyInner<T>) -> ScopedKey<T> { + ScopedKey { inner: inner } } /// Inserts a value into this scoped thread local storage slot for a @@ -153,13 +165,14 @@ impl<T> ScopedKey<T> { } } + let inner = (self.inner)(); let prev = unsafe { - let prev = self.inner.get(); - self.inner.set(t as *const T as *mut T); + let prev = inner.get(); + inner.set(t as *const T as *mut T); prev }; - let _reset = Reset { key: &self.inner, val: prev }; + let _reset = Reset { key: inner, val: prev }; cb() } @@ -186,7 +199,7 @@ impl<T> ScopedKey<T> { F: FnOnce(&T) -> R { unsafe { - let ptr = self.inner.get(); + let ptr = (self.inner)().get(); assert!(!ptr.is_null(), "cannot access a scoped thread local \ variable without calling `set` first"); cb(&*ptr) @@ -195,7 +208,7 @@ impl<T> ScopedKey<T> { /// Test whether this TLS key has been `set` for the current thread. pub fn is_set(&'static self) -> bool { - unsafe { !self.inner.get().is_null() } + unsafe { !(self.inner)().get().is_null() } } } @@ -205,6 +218,7 @@ impl<T> ScopedKey<T> { target_os = "openbsd", target_arch = "aarch64", no_elf_tls)))] +#[doc(hidden)] mod imp { use std::cell::Cell; @@ -227,6 +241,7 @@ mod imp { target_os = "openbsd", target_arch = "aarch64", no_elf_tls))] +#[doc(hidden)] mod imp { use prelude::v1::*; diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index ec3006898f3..e7d242ab703 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -1042,21 +1042,31 @@ impl<'a> MethodDef<'a> { /// variants where all of the variants match, and one catch-all for /// when one does not match. + /// As an optimization we generate code which checks whether all variants + /// match first which makes llvm see that C-like enums can be compiled into + /// a simple equality check (for PartialEq). + /// The catch-all handler is provided access the variant index values - /// for each of the self-args, carried in precomputed variables. (Nota - /// bene: the variant index values are not necessarily the - /// discriminant values. See issue #15523.) + /// for each of the self-args, carried in precomputed variables. /// ```{.text} - /// match (this, that, ...) { - /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1 - /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2 - /// ... - /// _ => { - /// let __this_vi = match this { Variant1 => 0, Variant2 => 1, ... }; - /// let __that_vi = match that { Variant1 => 0, Variant2 => 1, ... }; + /// let __self0_vi = unsafe { + /// std::intrinsics::discriminant_value(&self) } as i32; + /// let __self1_vi = unsafe { + /// std::intrinsics::discriminant_value(&__arg1) } as i32; + /// let __self2_vi = unsafe { + /// std::intrinsics::discriminant_value(&__arg2) } as i32; + /// + /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { + /// match (...) { + /// (Variant1, Variant1, ...) => Body1 + /// (Variant2, Variant2, ...) => Body2, + /// ... + /// _ => ::core::intrinsics::unreachable() + /// } + /// } + /// else { /// ... // catch-all remainder can inspect above variant index values. - /// } /// } /// ``` fn build_enum_match_tuple<'b>( @@ -1187,7 +1197,6 @@ impl<'a> MethodDef<'a> { cx.arm(sp, vec![single_pat], arm_expr) }).collect(); - // We will usually need the catch-all after matching the // tuples `(VariantK, VariantK, ...)` for each VariantK of the // enum. But: @@ -1223,9 +1232,14 @@ impl<'a> MethodDef<'a> { // ``` let mut index_let_stmts: Vec<P<ast::Stmt>> = Vec::new(); + //We also build an expression which checks whether all discriminants are equal + // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... + let mut discriminant_test = cx.expr_bool(sp, true); + let target_type_name = find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs); + let mut first_ident = None; for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { let path = vec![cx.ident_of_std("core"), cx.ident_of("intrinsics"), @@ -1243,32 +1257,64 @@ impl<'a> MethodDef<'a> { let variant_disr = cx.expr_cast(sp, variant_value, target_ty); let let_stmt = cx.stmt_let(sp, false, ident, variant_disr); index_let_stmts.push(let_stmt); + + match first_ident { + Some(first) => { + let first_expr = cx.expr_ident(sp, first); + let id = cx.expr_ident(sp, ident); + let test = cx.expr_binary(sp, ast::BiEq, first_expr, id); + discriminant_test = cx.expr_binary(sp, ast::BiAnd, discriminant_test, test) + } + None => { + first_ident = Some(ident); + } + } } let arm_expr = self.call_substructure_method( cx, trait_, type_ident, &self_args[..], nonself_args, &catch_all_substructure); - // Builds the expression: - // { - // let __self0_vi = ...; - // let __self1_vi = ...; - // ... - // <delegated expression referring to __self0_vi, et al.> - // } - let arm_expr = cx.expr_block( - cx.block_all(sp, index_let_stmts, Some(arm_expr))); - - // Builds arm: - // _ => { let __self0_vi = ...; - // let __self1_vi = ...; - // ... - // <delegated expression as above> } - let catch_all_match_arm = - cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr); - - match_arms.push(catch_all_match_arm); - + //Since we know that all the arguments will match if we reach the match expression we + //add the unreachable intrinsics as the result of the catch all which should help llvm + //in optimizing it + let path = vec![cx.ident_of_std("core"), + cx.ident_of("intrinsics"), + cx.ident_of("unreachable")]; + let call = cx.expr_call_global( + sp, path, vec![]); + let unreachable = cx.expr_block(P(ast::Block { + stmts: vec![], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: sp })); + match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], unreachable)); + + // Final wrinkle: the self_args are expressions that deref + // down to desired l-values, but we cannot actually deref + // them when they are fed as r-values into a tuple + // expression; here add a layer of borrowing, turning + // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. + let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); + let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); + + //Lastly we create an expression which branches on all discriminants being equal + // if discriminant_test { + // match (...) { + // (Variant1, Variant1, ...) => Body1 + // (Variant2, Variant2, ...) => Body2, + // ... + // _ => ::core::intrinsics::unreachable() + // } + // } + // else { + // <delegated expression referring to __self0_vi, et al.> + // } + let all_match = cx.expr_match(sp, match_arg, match_arms); + let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr)); + cx.expr_block( + cx.block_all(sp, index_let_stmts, Some(arm_expr))) } else if variants.is_empty() { // As an additional wrinkle, For a zero-variant enum A, // currently the compiler @@ -1319,17 +1365,19 @@ impl<'a> MethodDef<'a> { // derive Debug on such a type could here generate code // that needs the feature gate enabled.) - return cx.expr_unreachable(sp); + cx.expr_unreachable(sp) + } + else { + + // Final wrinkle: the self_args are expressions that deref + // down to desired l-values, but we cannot actually deref + // them when they are fed as r-values into a tuple + // expression; here add a layer of borrowing, turning + // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. + let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); + let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); + cx.expr_match(sp, match_arg, match_arms) } - - // Final wrinkle: the self_args are expressions that deref - // down to desired l-values, but we cannot actually deref - // them when they are fed as r-values into a tuple - // expression; here add a layer of borrowing, turning - // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`. - let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg)); - let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args)); - cx.expr_match(sp, match_arg, match_arms) } fn expand_static_enum_method_body(&self, diff --git a/src/llvm b/src/llvm -Subproject bff69076975642c64e76dbeaa53476bfa721208 +Subproject 8cbcdf1b72e1b23679646f6faca265f76b20d37 diff --git a/src/rustllvm/ExecutionEngineWrapper.cpp b/src/rustllvm/ExecutionEngineWrapper.cpp index bd4fcc0fc7d..df83f32670c 100644 --- a/src/rustllvm/ExecutionEngineWrapper.cpp +++ b/src/rustllvm/ExecutionEngineWrapper.cpp @@ -103,9 +103,6 @@ extern "C" LLVMExecutionEngineRef LLVMBuildExecutionEngine(LLVMModuleRef mod) std::string error_str; TargetOptions options; - options.JITEmitDebugInfo = true; - options.NoFramePointerElim = true; - RustJITMemoryManager *mm = new RustJITMemoryManager; ExecutionEngine *ee = diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index a2ab8040198..2c0240eb8f9 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -15,12 +15,19 @@ #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" +#if LLVM_VERSION_MINOR >= 7 +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#else #include "llvm/Target/TargetLibraryInfo.h" +#endif #include "llvm/Transforms/IPO/PassManagerBuilder.h" + #include "llvm-c/Transforms/PassManagerBuilder.h" using namespace llvm; +using namespace llvm::legacy; extern cl::opt<bool> EnableARMEHABI; @@ -71,7 +78,6 @@ LLVMRustCreateTargetMachine(const char *triple, CodeGenOpt::Level OptLevel, bool EnableSegmentedStacks, bool UseSoftFloat, - bool NoFramePointerElim, bool PositionIndependentExecutable, bool FunctionSections, bool DataSections) { @@ -91,12 +97,12 @@ LLVMRustCreateTargetMachine(const char *triple, TargetOptions Options; Options.PositionIndependentExecutable = PositionIndependentExecutable; - Options.NoFramePointerElim = NoFramePointerElim; Options.FloatABIType = FloatABI::Default; - Options.UseSoftFloat = UseSoftFloat; if (UseSoftFloat) { Options.FloatABIType = FloatABI::Soft; } + Options.DataSections = DataSections; + Options.FunctionSections = FunctionSections; TargetMachine *TM = TheTarget->createTargetMachine(Trip.getTriple(), real_cpu, @@ -105,8 +111,6 @@ LLVMRustCreateTargetMachine(const char *triple, RM, CM, OptLevel); - TM->setDataSections(DataSections); - TM->setFunctionSections(FunctionSections); return wrap(TM); } @@ -123,12 +127,32 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, LLVMPassManagerRef PMR, LLVMModuleRef M) { PassManagerBase *PM = unwrap(PMR); -#if LLVM_VERSION_MINOR >= 6 +#if LLVM_VERSION_MINOR >= 7 + PM->add(createTargetTransformInfoWrapperPass( + unwrap(TM)->getTargetIRAnalysis())); +#else +#if LLVM_VERSION_MINOR == 6 PM->add(new DataLayoutPass()); #else PM->add(new DataLayoutPass(unwrap(M))); #endif unwrap(TM)->addAnalysisPasses(*PM); +#endif +} + +extern "C" void +LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB, + CodeGenOpt::Level OptLevel, + bool MergeFunctions, + bool SLPVectorize, + bool LoopVectorize) { +#if LLVM_VERSION_MINOR >= 6 + // Ignore mergefunc for now as enabling it causes crashes. + //unwrap(PMB)->MergeFunctions = MergeFunctions; +#endif + unwrap(PMB)->SLPVectorize = SLPVectorize; + unwrap(PMB)->OptLevel = OptLevel; + unwrap(PMB)->LoopVectorize = LoopVectorize; } // Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo` @@ -138,7 +162,11 @@ LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M, bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); +#if LLVM_VERSION_MINOR >= 7 + TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple); +#else TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); +#endif if (DisableSimplifyLibCalls) TLI->disableAllFunctions(); unwrap(PMB)->LibraryInfo = TLI; @@ -151,10 +179,17 @@ LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M, bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); +#if LLVM_VERSION_MINOR >= 7 + TargetLibraryInfoImpl TLII(TargetTriple); + if (DisableSimplifyLibCalls) + TLII.disableAllFunctions(); + unwrap(PMB)->add(new TargetLibraryInfoWrapperPass(TLII)); +#else TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); if (DisableSimplifyLibCalls) TLI->disableAllFunctions(); unwrap(PMB)->add(TLI); +#endif } // Unfortunately, the LLVM C API doesn't provide an easy way of iterating over @@ -204,10 +239,19 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMRustSetLastError(ErrorInfo.c_str()); return false; } - formatted_raw_ostream FOS(OS); +#if LLVM_VERSION_MINOR >= 7 + unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false); +#else + formatted_raw_ostream FOS(OS); unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false); +#endif PM->run(*unwrap(M)); + + // Apparently `addPassesToEmitFile` adds an pointer to our on-the-stack output + // stream (OS), so the only real safe place to delete this is here? Don't we + // wish this was written in Rust? + delete PM; return true; } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index ad6533e5480..70ef64afc43 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -141,6 +141,15 @@ extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); } +extern "C" void LLVMAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index, + const char *Name, + const char *Value) { + Function *F = unwrap<Function>(Fn); + AttrBuilder B; + B.addAttribute(Name, Value); + F->addAttributes(index, AttributeSet::get(F->getContext(), index, B)); +} + extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) { Function *f = unwrap<Function>(fn); LLVMContext &C = f->getContext(); @@ -229,9 +238,24 @@ typedef LLVMValueRef LLVMMetadataRef; #endif template<typename DIT> +DIT* unwrapDIptr(LLVMMetadataRef ref) { + return (DIT*) (ref ? unwrap<MDNode>(ref) : NULL); +} + +#if LLVM_VERSION_MINOR <= 6 +template<typename DIT> DIT unwrapDI(LLVMMetadataRef ref) { return DIT(ref ? unwrap<MDNode>(ref) : NULL); } +#else +#define DIDescriptor DIScope +#define DIArray DINodeArray +#define unwrapDI unwrapDIptr +#endif + +#if LLVM_VERSION_MINOR <= 5 +#define DISubroutineType DICompositeType +#endif extern "C" uint32_t LLVMRustDebugMetadataVersion() { return DEBUG_METADATA_VERSION; @@ -296,7 +320,9 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateSubroutineType( LLVMMetadataRef ParameterTypes) { return wrap(Builder->createSubroutineType( unwrapDI<DIFile>(File), -#if LLVM_VERSION_MINOR >= 6 +#if LLVM_VERSION_MINOR >= 7 + DITypeRefArray(unwrap<MDTuple>(ParameterTypes)))); +#elif LLVM_VERSION_MINOR >= 6 unwrapDI<DITypeArray>(ParameterTypes))); #else unwrapDI<DIArray>(ParameterTypes))); @@ -322,11 +348,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateFunction( return wrap(Builder->createFunction( unwrapDI<DIScope>(Scope), Name, LinkageName, unwrapDI<DIFile>(File), LineNo, - unwrapDI<DICompositeType>(Ty), isLocalToUnit, isDefinition, ScopeLine, + unwrapDI<DISubroutineType>(Ty), isLocalToUnit, isDefinition, ScopeLine, Flags, isOptimized, unwrap<Function>(Fn), - unwrapDI<MDNode*>(TParam), - unwrapDI<MDNode*>(Decl))); + unwrapDIptr<MDNode>(TParam), + unwrapDIptr<MDNode>(Decl))); } extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType( @@ -373,7 +399,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStructType( AlignInBits, Flags, unwrapDI<DIType>(DerivedFrom), +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI<MDTuple>(Elements)), +#else unwrapDI<DIArray>(Elements), +#endif RunTimeLang, unwrapDI<DIType>(VTableHolder), UniqueId @@ -436,7 +466,7 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateStaticVariable( unwrapDI<DIType>(Ty), isLocalToUnit, cast<Constant>(unwrap(Val)), - unwrapDI<MDNode*>(Decl))); + unwrapDIptr<MDNode>(Decl))); } extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable( @@ -486,7 +516,12 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType( LLVMMetadataRef Subscripts) { return wrap(Builder->createArrayType(Size, AlignInBits, unwrapDI<DIType>(Ty), - unwrapDI<DIArray>(Subscripts))); +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI<MDTuple>(Subscripts)) +#else + unwrapDI<DIArray>(Subscripts) +#endif + )); } extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType( @@ -497,7 +532,12 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType( LLVMMetadataRef Subscripts) { return wrap(Builder->createVectorType(Size, AlignInBits, unwrapDI<DIType>(Ty), - unwrapDI<DIArray>(Subscripts))); +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI<MDTuple>(Subscripts)) +#else + unwrapDI<DIArray>(Subscripts) +#endif + )); } extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange( @@ -511,12 +551,18 @@ extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateArray( DIBuilderRef Builder, LLVMMetadataRef* Ptr, unsigned Count) { +#if LLVM_VERSION_MINOR >= 7 + Metadata **DataValue = unwrap(Ptr); + return wrap(Builder->getOrCreateArray( + ArrayRef<Metadata*>(DataValue, Count)).get()); +#else return wrap(Builder->getOrCreateArray( #if LLVM_VERSION_MINOR >= 6 ArrayRef<Metadata*>(unwrap(Ptr), Count))); #else ArrayRef<Value*>(reinterpret_cast<Value**>(Ptr), Count))); #endif +#endif } extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( @@ -525,21 +571,21 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( LLVMMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, + LLVMValueRef DL, LLVMBasicBlockRef InsertAtEnd) { -#if LLVM_VERSION_MINOR >= 6 - DIExpression Expr; - if (AddrOpsCount == 0) { - Expr = Builder->createExpression(); - } else { - llvm::ArrayRef<int64_t> addr_ops(AddrOps, AddrOpsCount); - Expr = Builder->createExpression(addr_ops); - } -#endif return wrap(Builder->insertDeclare( unwrap(Val), +#if LLVM_VERSION_MINOR >= 7 + unwrap<DILocalVariable>(VarInfo), +#else unwrapDI<DIVariable>(VarInfo), +#endif #if LLVM_VERSION_MINOR >= 6 - Expr, + Builder->createExpression( + llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)), +#endif +#if LLVM_VERSION_MINOR >= 7 + DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())), #endif unwrap(InsertAtEnd))); } @@ -550,21 +596,23 @@ extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore( LLVMMetadataRef VarInfo, int64_t* AddrOps, unsigned AddrOpsCount, + LLVMValueRef DL, LLVMValueRef InsertBefore) { #if LLVM_VERSION_MINOR >= 6 - DIExpression Expr; - if (AddrOpsCount == 0) { - Expr = Builder->createExpression(); - } else { - llvm::ArrayRef<int64_t> addr_ops(AddrOps, AddrOpsCount); - Expr = Builder->createExpression(addr_ops); - } #endif return wrap(Builder->insertDeclare( unwrap(Val), +#if LLVM_VERSION_MINOR >= 7 + unwrap<DILocalVariable>(VarInfo), +#else unwrapDI<DIVariable>(VarInfo), +#endif #if LLVM_VERSION_MINOR >= 6 - Expr, + Builder->createExpression( + llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)), +#endif +#if LLVM_VERSION_MINOR >= 7 + DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())), #endif unwrap<Instruction>(InsertBefore))); } @@ -595,7 +643,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( LineNumber, SizeInBits, AlignInBits, +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI<MDTuple>(Elements)), +#else unwrapDI<DIArray>(Elements), +#endif unwrapDI<DIType>(ClassType))); } @@ -620,7 +672,11 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateUnionType( SizeInBits, AlignInBits, Flags, +#if LLVM_VERSION_MINOR >= 7 + DINodeArray(unwrapDI<MDTuple>(Elements)), +#else unwrapDI<DIArray>(Elements), +#endif RunTimeLang, UniqueId )); @@ -638,10 +694,14 @@ extern "C" LLVMMetadataRef LLVMDIBuilderCreateTemplateTypeParameter( return wrap(Builder->createTemplateTypeParameter( unwrapDI<DIDescriptor>(Scope), Name, - unwrapDI<DIType>(Ty), + unwrapDI<DIType>(Ty) +#if LLVM_VERSION_MINOR <= 6 + , unwrapDI<MDNode*>(File), LineNo, - ColumnNo)); + ColumnNo +#endif + )); } extern "C" int64_t LLVMDIBuilderCreateOpDeref() @@ -673,7 +733,10 @@ extern "C" void LLVMDICompositeTypeSetTypeArray( LLVMMetadataRef CompositeType, LLVMMetadataRef TypeArray) { -#if LLVM_VERSION_MINOR >= 6 +#if LLVM_VERSION_MINOR >= 7 + DICompositeType *tmp = unwrapDI<DICompositeType>(CompositeType); + Builder->replaceArrays(tmp, DINodeArray(unwrap<MDTuple>(TypeArray))); +#elif LLVM_VERSION_MINOR >= 6 DICompositeType tmp = unwrapDI<DICompositeType>(CompositeType); Builder->replaceArrays(tmp, unwrapDI<DIArray>(TypeArray)); #else @@ -692,11 +755,15 @@ extern "C" LLVMValueRef LLVMDIBuilderCreateDebugLocation( DebugLoc debug_loc = DebugLoc::get(Line, Column, - unwrapDI<MDNode*>(Scope), - unwrapDI<MDNode*>(InlinedAt)); + unwrapDIptr<MDNode>(Scope), + unwrapDIptr<MDNode>(InlinedAt)); #if LLVM_VERSION_MINOR >= 6 - return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode(context))); + return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode( +#if LLVM_VERSION_MINOR <= 6 + context +#endif + ))); #else return wrap(debug_loc.getAsMDNode(context)); #endif @@ -721,7 +788,12 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { Module *Dst = unwrap(dst); #if LLVM_VERSION_MINOR >= 6 std::unique_ptr<MemoryBuffer> buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len)); +#if LLVM_VERSION_MINOR >= 7 + ErrorOr<std::unique_ptr<Module>> Src = + llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext()); +#else ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext()); +#endif #else MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len)); ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(buf, Dst->getContext()); @@ -739,7 +811,11 @@ LLVMRustLinkInExternalBitcode(LLVMModuleRef dst, char *bc, size_t len) { #if LLVM_VERSION_MINOR >= 6 raw_string_ostream Stream(Err); DiagnosticPrinterRawOStream DP(Stream); +#if LLVM_VERSION_MINOR >= 7 + if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) { +#else if (Linker::LinkModules(Dst, *Src, [&](const DiagnosticInfo &DI) { DI.print(DP); })) { +#endif #else if (Linker::LinkModules(Dst, *Src, Linker::DestroySource, &Err)) { #endif @@ -813,8 +889,12 @@ extern "C" const Archive::Child* LLVMRustArchiveIteratorCurrent(RustArchiveIterator *rai) { if (rai->cur == rai->end) return NULL; +#if LLVM_VERSION_MINOR >= 6 const Archive::Child &ret = *rai->cur; return &ret; +#else + return rai->cur.operator->(); +#endif } extern "C" void @@ -942,7 +1022,11 @@ extern "C" void LLVMWriteDebugLocToString( RustStringRef str) { raw_rust_string_ostream os(str); +#if LLVM_VERSION_MINOR >= 7 + unwrap(dl)->print(os); +#else unwrap(dl)->print(*unwrap(C), os); +#endif } DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 1ea40fc46a5..38b7b49a344 100644 --- a/src/rustllvm/llvm-auto-clean-trigger +++ b/src/rustllvm/llvm-auto-clean-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be forcibly cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2015-03-04 +2015-06-16 diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index bb82c0c8186..2a47e8b0895 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -12,7 +12,6 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/PassManager.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Analysis/Passes.h" @@ -46,6 +45,12 @@ #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Object.h" +#if LLVM_VERSION_MINOR >= 7 +#include "llvm/IR/LegacyPassManager.h" +#else +#include "llvm/PassManager.h" +#endif + #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DIBuilder.h" diff --git a/src/test/auxiliary/llvm_pass_plugin.rs b/src/test/auxiliary/llvm_pass_plugin.rs index d61f47fd7ef..bacc1acd3c4 100644 --- a/src/test/auxiliary/llvm_pass_plugin.rs +++ b/src/test/auxiliary/llvm_pass_plugin.rs @@ -24,5 +24,5 @@ pub fn plugin_registrar(reg: &mut Registry) { // Normally, we would name a pass that was registered through // C++ static object constructors in the same .so file as the // plugin registrar. - reg.register_llvm_pass("inline"); + reg.register_llvm_pass("gvn"); } diff --git a/src/test/codegen/loads.rs b/src/test/codegen/loads.rs index 20a55740bb7..45b8731c3b1 100644 --- a/src/test/codegen/loads.rs +++ b/src/test/codegen/loads.rs @@ -20,14 +20,14 @@ pub struct Bytes { // CHECK-LABEL: @borrow #[no_mangle] pub fn borrow(x: &i32) -> &i32 { -// CHECK: load i32** %x{{.*}}, !nonnull +// CHECK: load i32*, i32** %x{{.*}}, !nonnull x } // CHECK-LABEL: @_box #[no_mangle] pub fn _box(x: Box<i32>) -> i32 { -// CHECK: load i32** %x{{.*}}, !nonnull +// CHECK: load i32*, i32** %x{{.*}}, !nonnull *x } @@ -36,7 +36,7 @@ pub fn _box(x: Box<i32>) -> i32 { // dependent alignment #[no_mangle] pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] { -// CHECK: [[VAR:%[0-9]+]] = load i32* %{{.*}}, align 1 +// CHECK: [[VAR:%[0-9]+]] = load i32, i32* %{{.*}}, align 1 // CHECK: ret i32 [[VAR]] x } @@ -46,7 +46,7 @@ pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] { // dependent alignment #[no_mangle] pub fn small_struct_alignment(x: Bytes) -> Bytes { -// CHECK: [[VAR:%[0-9]+]] = load i32* %{{.*}}, align 1 +// CHECK: [[VAR:%[0-9]+]] = load i32, i32* %{{.*}}, align 1 // CHECK: ret i32 [[VAR]] x } diff --git a/src/test/codegen/stores.rs b/src/test/codegen/stores.rs index 32337b085cd..15cf76b2ab1 100644 --- a/src/test/codegen/stores.rs +++ b/src/test/codegen/stores.rs @@ -22,7 +22,7 @@ pub struct Bytes { // dependent alignment #[no_mangle] pub fn small_array_alignment(x: &mut [i8; 4]) { -// CHECK: [[VAR:%[0-9]+]] = load [4 x i8]** %x +// CHECK: [[VAR:%[0-9]+]] = load [4 x i8]*, [4 x i8]** %x // CHECK: [[VAR2:%[0-9]+]] = bitcast [4 x i8]* [[VAR]] to i32* // CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1 *x = [0; 4]; @@ -33,7 +33,7 @@ pub fn small_array_alignment(x: &mut [i8; 4]) { // dependent alignment #[no_mangle] pub fn small_struct_alignment(x: &mut Bytes) { -// CHECK: [[VAR:%[0-9]+]] = load %Bytes** %x +// CHECK: [[VAR:%[0-9]+]] = load %Bytes*, %Bytes** %x // CHECK: [[VAR2:%[0-9]+]] = bitcast %Bytes* [[VAR]] to i32* // CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1 *x = Bytes { diff --git a/src/test/compile-fail/issue-26262.rs b/src/test/compile-fail/issue-26262.rs new file mode 100644 index 00000000000..8d79fd4570d --- /dev/null +++ b/src/test/compile-fail/issue-26262.rs @@ -0,0 +1,32 @@ +// 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 <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. + +// Check that projections don't count as constraining type parameters. + +struct S<T>(T); + +trait Tr { type Assoc; fn test(); } + +impl<T: Tr> S<T::Assoc> { +//~^ ERROR the type parameter `T` is not constrained + fn foo(self, _: T) { + T::test(); + } +} + +trait Trait1<T> { type Bar; } +trait Trait2<'x> { type Foo; } + +impl<'a,T: Trait2<'a>> Trait1<<T as Trait2<'a>>::Foo> for T { +//~^ ERROR the lifetime parameter `'a` is not constrained + type Bar = &'a (); +} + +fn main() {} diff --git a/src/test/compile-fail/lint-dead-code-variant.rs b/src/test/compile-fail/lint-dead-code-variant.rs new file mode 100644 index 00000000000..0116d63caf2 --- /dev/null +++ b/src/test/compile-fail/lint-dead-code-variant.rs @@ -0,0 +1,22 @@ +// 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 <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. + +#![deny(dead_code)] + +#[derive(Clone)] +enum Enum { + Variant1, //~ ERROR: variant is never used + Variant2, +} + +fn main() { + let e = Enum::Variant2; + e.clone(); +} diff --git a/src/test/run-pass/asm-in-out-operand.rs b/src/test/run-pass/asm-in-out-operand.rs index 3eebc7acb0f..243ecf86e9c 100644 --- a/src/test/run-pass/asm-in-out-operand.rs +++ b/src/test/run-pass/asm-in-out-operand.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - #![feature(asm)] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] unsafe fn next_power_of_2(n: u32) -> u32 { let mut tmp = n; asm!("dec $0" : "+rm"(tmp) :: "cc"); - let mut shift = 1_usize; + let mut shift = 1_u32; while shift <= 16 { asm!( "shr %cl, $2 diff --git a/src/test/run-pass/associated-types-method.rs b/src/test/run-pass/associated-types-method.rs new file mode 100644 index 00000000000..b57687a49fa --- /dev/null +++ b/src/test/run-pass/associated-types-method.rs @@ -0,0 +1,36 @@ +// 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 <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. + +// Test that methods whose impl-trait-ref contains associated types +// are supported. + +trait Device { + type Resources; +} +struct Foo<D, R>(D, R); + +trait Tr { + fn present(&self) {} +} + +impl<D: Device> Tr for Foo<D, D::Resources> { + fn present(&self) {} +} + +struct Res; +struct Dev; +impl Device for Dev { + type Resources = Res; +} + +fn main() { + let foo = Foo(Dev, Res); + foo.present(); +} diff --git a/src/test/run-pass/issue-25089.rs b/src/test/run-pass/issue-25089.rs new file mode 100644 index 00000000000..b619d1dd448 --- /dev/null +++ b/src/test/run-pass/issue-25089.rs @@ -0,0 +1,40 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::thread; + +struct Foo(i32); + +impl Drop for Foo { + fn drop(&mut self) { + static mut DROPPED: bool = false; + unsafe { + assert!(!DROPPED); + DROPPED = true; + } + } +} + +struct Empty; + +fn empty() -> Empty { Empty } + +fn should_panic(_: Foo, _: Empty) { + panic!("test panic"); +} + +fn test() { + should_panic(Foo(1), empty()); +} + +fn main() { + let ret = thread::spawn(test).join(); + assert!(ret.is_err()); +} diff --git a/src/test/run-pass/issue-25679.rs b/src/test/run-pass/issue-25679.rs new file mode 100644 index 00000000000..0ba7feece60 --- /dev/null +++ b/src/test/run-pass/issue-25679.rs @@ -0,0 +1,28 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Device { + type Resources; +} +struct Foo<D, R>(D, R); + +impl<D: Device> Foo<D, D::Resources> { + fn present(&self) {} +} + +struct Res; +struct Dev; + +impl Device for Dev { type Resources = Res; } + +fn main() { + let foo = Foo(Dev, Res); + foo.present(); +} diff --git a/src/test/run-pass/lint-dead-code-variant.rs b/src/test/run-pass/lint-dead-code-variant.rs new file mode 100644 index 00000000000..074c69d8708 --- /dev/null +++ b/src/test/run-pass/lint-dead-code-variant.rs @@ -0,0 +1,22 @@ +// 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 <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. + +#![deny(dead_code)] + +enum Foo { + A, + B, +} + +pub fn main() { + match Foo::A { + Foo::A | Foo::B => Foo::B + }; +} diff --git a/src/test/run-pass/sync-send-iterators-in-libcore.rs b/src/test/run-pass/sync-send-iterators-in-libcore.rs index 969cf853f05..cd99b39fdd0 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcore.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcore.rs @@ -10,28 +10,101 @@ // pretty-expanded FIXME #23616 +#![allow(unused_mut)] +#![feature(core)] #![feature(collections)] +#![feature(step_by)] +#![feature(iter_empty)] +#![feature(iter_once)] + +use std::iter::{empty, once, range_inclusive, repeat, Unfold}; fn is_sync<T>(_: T) where T: Sync {} fn is_send<T>(_: T) where T: Send {} macro_rules! all_sync_send { + ($ctor:expr, $iter:ident) => ({ + let mut x = $ctor; + is_sync(x.$iter()); + let mut y = $ctor; + is_send(y.$iter()); + }); + ($ctor:expr, $iter:ident($($param:expr),+)) => ({ + let mut x = $ctor; + is_sync(x.$iter($( $param ),+)); + let mut y = $ctor; + is_send(y.$iter($( $param ),+)); + }); + ($ctor:expr, $iter:ident, $($rest:tt)*) => ({ + all_sync_send!($ctor, $iter); + all_sync_send!($ctor, $($rest)*); + }); + ($ctor:expr, $iter:ident($($param:expr),+), $($rest:tt)*) => ({ + all_sync_send!($ctor, $iter($( $param ),+)); + all_sync_send!($ctor, $($rest)*); + }); +} + +macro_rules! all_sync_send_mutable_ref { ($ctor:expr, $($iter:ident),+) => ({ $( let mut x = $ctor; - is_sync(x.$iter()); + is_sync((&mut x).$iter()); let mut y = $ctor; - is_send(y.$iter()); + is_send((&mut y).$iter()); )+ }) } +macro_rules! is_sync_send { + ($ctor:expr) => ({ + let x = $ctor; + is_sync(x); + let y = $ctor; + is_send(y); + }) +} + fn main() { // for char.rs all_sync_send!("Я", escape_default, escape_unicode); // for iter.rs - // FIXME + all_sync_send_mutable_ref!([1], iter); + + // Bytes implements DoubleEndedIterator + all_sync_send!("a".bytes(), rev); + + let a = [1]; + let b = [2]; + all_sync_send!(a.iter(), + cloned, + cycle, + chain([2].iter()), + zip([2].iter()), + map(|_| 1), + filter(|_| true), + filter_map(|_| Some(1)), + enumerate, + peekable, + skip_while(|_| true), + take_while(|_| true), + skip(1), + take(1), + scan(1, |_, _| Some(1)), + flat_map(|_| b.iter()), + fuse, + inspect(|_| ())); + + is_sync_send!(Unfold::new(Some(1), |&mut v| v)); + is_sync_send!((1..).step_by(2)); + is_sync_send!(range_inclusive(1, 1)); + is_sync_send!((1..2).step_by(2)); + is_sync_send!((1..2)); + is_sync_send!((1..)); + is_sync_send!(repeat(1)); + is_sync_send!(empty::<usize>()); + is_sync_send!(once(1)); // for option.rs // FIXME |
