From bce7a6f4a9edd23c73bf4fc390db3037895c1850 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 21 Jan 2015 23:07:23 +0900 Subject: [PATCH 01/12] Remove dead code flagged by lint --- src/libtest/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 0692d7e5faa..6f85b630609 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -118,6 +118,7 @@ impl fmt::Display for TestName { #[derive(Clone, Copy)] enum NamePadding { PadNone, + #[allow(dead_code)] PadOnLeft, PadOnRight, } From b042ffc4a768c2bd6d7588b1b2f47af22669c2cb Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 21 Jan 2015 23:10:53 +0900 Subject: [PATCH 02/12] Extend dead code lint to detect more unused enum variants --- src/librustc/middle/dead.rs | 28 ++++++++++++- src/librustc/middle/pat_util.rs | 24 +++++++++++ .../compile-fail/lint-dead-code-variant.rs | 42 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/lint-dead-code-variant.rs diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 4478e327087..05265231fb8 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -47,6 +47,7 @@ struct MarkSymbolVisitor<'a, 'tcx: 'a> { struct_has_extern_repr: bool, ignore_non_const_paths: bool, inherited_pub_visibility: bool, + ignore_variant_stack: Vec, } impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { @@ -59,6 +60,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![], } } @@ -79,7 +81,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()); @@ -283,6 +287,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 { @@ -401,6 +422,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 01dc55c3eee..7de5349d09c 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -140,3 +140,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 { + 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(&DefVariant(_, id, _)) => { + variants.push(id.node); + } + _ => () + } + } + _ => () + } + true + }); + variants.sort(); + variants.dedup(); + variants +} 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..6146be65e38 --- /dev/null +++ b/src/test/compile-fail/lint-dead-code-variant.rs @@ -0,0 +1,42 @@ +// 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. + +#![deny(dead_code)] + +#[derive(Copy)] +enum Enum { + Variant1, //~ ERROR: variant is never used + Variant2, + Variant3, +} + +fn copy(e: Enum) -> Enum { + use Enum::*; + match e { + Variant1 => Variant1, + Variant2 => Variant2, + Variant3 => Variant3, + } +} + +fn max(e: Enum) -> Enum { + use Enum::*; + match e { + Variant1 => Variant3, + Variant2 => Variant3, + Variant3 => Variant3, + } +} + +fn main() { + let e = Enum::Variant2; + copy(e); + max(e); +} From de52403295e66ee413f1085e8b9defe7d81b9751 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 12 Mar 2015 04:09:12 -0700 Subject: [PATCH 03/12] Avoid passing -L "" to rustc. Currently, target.mk passes -L "" when LLVM_STDCPP_LOCATION_$(2) is empty. This fixes #23287. --- mk/llvm.mk | 6 +++--- mk/target.mk | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mk/llvm.mk b/mk/llvm.mk index b07c2a1d62f..1861dd313ce 100644 --- a/mk/llvm.mk +++ b/mk/llvm.mk @@ -44,10 +44,10 @@ $$(LLVM_STAMP_$(1)): $(S)src/rustllvm/llvm-auto-clean-trigger touch -r $$@.start_time $$@ && rm $$@.start_time ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1) -LLVM_STDCPP_LOCATION_$(1) = $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ - -print-file-name=libstdc++.a) +LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \ + -print-file-name=libstdc++.a))" else -LLVM_STDCPP_LOCATION_$(1) = +LLVM_STDCPP_RUSTFLAGS_$(1) = endif diff --git a/mk/target.mk b/mk/target.mk index 2435edfb9dc..4182ec81a7e 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -85,7 +85,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \ $$(RUST_LIB_FLAGS_ST$(1)) \ -L "$$(RT_OUTPUT_DIR_$(2))" \ -L "$$(LLVM_LIBDIR_$(2))" \ - -L "$$(dir $$(LLVM_STDCPP_LOCATION_$(2)))" \ + $$(LLVM_STDCPP_RUSTFLAGS_$(2)) \ $$(RUSTFLAGS_$(4)) \ --out-dir $$(@D) \ -C extra-filename=-$$(CFG_FILENAME_EXTRA) \ From 90fc28d0f26c02b6071c18f586df554d6e305b1f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 12 Mar 2015 17:05:44 +0100 Subject: [PATCH 04/12] debuginfo: Add GDB pretty printers for slices, Vec<>, and String. --- src/etc/gdb_rust_pretty_printing.py | 89 +++++++++++++++++++++++++++- src/test/debuginfo/gdb-pretty-std.rs | 60 +++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 src/test/debuginfo/gdb-pretty-std.rs diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index c5587bb10d1..dbf27e88c14 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -27,9 +27,18 @@ def rust_pretty_printer_lookup_function(val): if type_code == gdb.TYPE_CODE_STRUCT: struct_kind = classify_struct(val.type) + if struct_kind == STRUCT_KIND_SLICE: + return RustSlicePrinter(val) + if struct_kind == STRUCT_KIND_STR_SLICE: return RustStringSlicePrinter(val) + if struct_kind == STRUCT_KIND_STD_VEC: + return RustStdVecPrinter(val) + + if struct_kind == STRUCT_KIND_STD_STRING: + return RustStdStringPrinter(val) + if struct_kind == STRUCT_KIND_TUPLE: return RustTuplePrinter(val) @@ -172,6 +181,28 @@ class RustTupleStructPrinter: def display_hint(self): return "array" +class RustSlicePrinter: + def __init__(self, val): + self.val = val + + def display_hint(self): + return "array" + + def to_string(self): + length = int(self.val["length"]) + return self.val.type.tag + ("(len: %i)" % length) + + def children(self): + cs = [] + length = int(self.val["length"]) + data_ptr = self.val["data_ptr"] + assert data_ptr.type.code == gdb.TYPE_CODE_PTR + pointee_type = data_ptr.type.target() + + for index in range(0, length): + cs.append((str(index), (data_ptr + index).dereference())) + + return cs class RustStringSlicePrinter: def __init__(self, val): @@ -181,6 +212,35 @@ class RustStringSlicePrinter: slice_byte_len = self.val["length"] return '"%s"' % self.val["data_ptr"].string(encoding="utf-8", length=slice_byte_len) +class RustStdVecPrinter: + def __init__(self, val): + self.val = val + + def display_hint(self): + return "array" + + def to_string(self): + length = int(self.val["len"]) + cap = int(self.val["cap"]) + return self.val.type.tag + ("(len: %i, cap: %i)" % (length, cap)) + + def children(self): + cs = [] + (length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val) + pointee_type = data_ptr.type.target() + + for index in range(0, length): + cs.append((str(index), (data_ptr + index).dereference())) + return cs + +class RustStdStringPrinter: + def __init__(self, val): + self.val = val + + def to_string(self): + (length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val["vec"]) + return '"%s"' % data_ptr.string(encoding="utf-8", length=length) + class RustCStyleEnumPrinter: def __init__(self, val): @@ -204,19 +264,38 @@ STRUCT_KIND_TUPLE = 2 STRUCT_KIND_TUPLE_VARIANT = 3 STRUCT_KIND_STRUCT_VARIANT = 4 STRUCT_KIND_CSTYLE_VARIANT = 5 -STRUCT_KIND_STR_SLICE = 6 +STRUCT_KIND_SLICE = 6 +STRUCT_KIND_STR_SLICE = 7 +STRUCT_KIND_STD_VEC = 8 +STRUCT_KIND_STD_STRING = 9 def classify_struct(type): + # print("\nclassify_struct: tag=%s\n" % type.tag) if type.tag == "&str": return STRUCT_KIND_STR_SLICE + if type.tag.startswith("&[") and type.tag.endswith("]"): + return STRUCT_KIND_SLICE + fields = list(type.fields()) field_count = len(fields) if field_count == 0: return STRUCT_KIND_REGULAR_STRUCT + if (field_count == 3 and + fields[0].name == "ptr" and + fields[1].name == "len" and + fields[2].name == "cap" and + type.tag.startswith("Vec<")): + return STRUCT_KIND_STD_VEC + + if (field_count == 1 and + fields[0].name == "vec" and + type.tag == "String"): + return STRUCT_KIND_STD_STRING + if fields[0].name == "RUST$ENUM$DISR": if field_count == 1: return STRUCT_KIND_CSTYLE_VARIANT @@ -254,3 +333,11 @@ def get_field_at_index(val, index): return field i += 1 return None + +def extract_length_and_data_ptr_from_std_vec(vec_val): + length = int(vec_val["len"]) + vec_ptr_val = vec_val["ptr"] + unique_ptr_val = vec_ptr_val[first_field(vec_ptr_val)] + data_ptr = unique_ptr_val[first_field(unique_ptr_val)] + assert data_ptr.type.code == gdb.TYPE_CODE_PTR + return (length, data_ptr) \ No newline at end of file diff --git a/src/test/debuginfo/gdb-pretty-std.rs b/src/test/debuginfo/gdb-pretty-std.rs new file mode 100644 index 00000000000..dbf80a9bccc --- /dev/null +++ b/src/test/debuginfo/gdb-pretty-std.rs @@ -0,0 +1,60 @@ +// Copyright 2013-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. + +// ignore-windows failing on win32 bot +// ignore-freebsd: gdb package too new +// ignore-tidy-linelength +// ignore-lldb +// ignore-android: FIXME(#10381) +// compile-flags:-g +// min-gdb-version 7.7 + +// gdb-command: run + +// gdb-command: print slice +// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3} + +// gdb-command: print vec +// gdb-check:$2 = Vec(len: 4, cap: [...]) = {4, 5, 6, 7} + +// gdb-command: print str_slice +// gdb-check:$3 = "IAMA string slice!" + +// gdb-command: print string +// gdb-check:$4 = "IAMA string!" + +// gdb-command: print some +// gdb-check:$5 = Some = {8} + +// gdb-command: print none +// gdb-check:$6 = None + +fn main() { + + // &[] + let slice: &[i32] = &[0, 1, 2, 3]; + + // Vec + let vec = vec![4u64, 5, 6, 7]; + + // &str + let str_slice = "IAMA string slice!"; + + // String + let string = "IAMA string!".to_string(); + + // Option + let some = Some(8i16); + let none: Option = None; + + zzz(); // #break +} + +fn zzz() { () } From 5d9ed0bc0e7922fb1fbdc518edc9bacb342fad6e Mon Sep 17 00:00:00 2001 From: Gleb Kozyrev Date: Thu, 12 Mar 2015 17:09:26 +0200 Subject: [PATCH 05/12] Update the ways to get a pointer from a box Show how to get a pointer without destroying the box. Use `boxed::into_raw` instead of `mem::transmute`. --- src/libcore/ptr.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 0625c3c7d60..32123a8271c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -33,31 +33,34 @@ //! let my_speed_ptr: *mut i32 = &mut my_speed; //! ``` //! +//! To get a pointer to a boxed value, dereference the box: +//! +//! ``` +//! let my_num: Box = Box::new(10); +//! let my_num_ptr: *const i32 = &*my_num; +//! let mut my_speed: Box = Box::new(88); +//! let my_speed_ptr: *mut i32 = &mut *my_speed; +//! ``` +//! //! This does not take ownership of the original allocation //! and requires no resource management later, //! but you must not use the pointer after its lifetime. //! -//! ## 2. Transmute an owned box (`Box`). +//! ## 2. Consume a box (`Box`). //! -//! The `transmute` function takes, by value, whatever it's given -//! and returns it as whatever type is requested, as long as the -//! types are the same size. Because `Box` and `*mut T` have the same -//! representation they can be trivially, -//! though unsafely, transformed from one type to the other. +//! The `into_raw` function consumes a box and returns +//! the raw pointer. It doesn't destroy `T` or deallocate any memory. //! //! ``` -//! use std::mem; +//! use std::boxed; //! //! unsafe { -//! let my_num: Box = Box::new(10); -//! let my_num: *const i32 = mem::transmute(my_num); //! let my_speed: Box = Box::new(88); -//! let my_speed: *mut i32 = mem::transmute(my_speed); +//! let my_speed: *mut i32 = boxed::into_raw(my_speed); //! //! // By taking ownership of the original `Box` though -//! // we are obligated to transmute it back later to be destroyed. -//! drop(mem::transmute::<_, Box>(my_speed)); -//! drop(mem::transmute::<_, Box>(my_num)); +//! // we are obligated to put it together later to be destroyed. +//! drop(Box::from_raw(my_speed)); //! } //! ``` //! From ccfc381044706c6edbfa6054a7e73684ec0f1da6 Mon Sep 17 00:00:00 2001 From: Trent Nadeau Date: Thu, 12 Mar 2015 17:00:35 -0400 Subject: [PATCH 06/12] Fixed several grammar errors and broke up very long line. --- src/doc/trpl/hello-cargo.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/hello-cargo.md b/src/doc/trpl/hello-cargo.md index d077aac7c2d..b45211e3a08 100644 --- a/src/doc/trpl/hello-cargo.md +++ b/src/doc/trpl/hello-cargo.md @@ -85,9 +85,11 @@ Hello, world! Bam! We build our project with `cargo build`, and run it with `./target/debug/hello_world`. This hasn't bought us a whole lot over our simple use of `rustc`, but think about the future: when our project has more than one -file, we would need to call `rustc` more than once, and pass it a bunch of options to +file, we would need to call `rustc` more than once and pass it a bunch of options to tell it to build everything together. With Cargo, as our project grows, we can -just `cargo build` and it'll work the right way. When you're project is finally ready for release, you can use `cargo build --release` to compile your crates with optimizations. +just `cargo build`, and it'll work the right way. When your project is finally +ready for release, you can use `cargo build --release` to compile your crates with +optimizations. You'll also notice that Cargo has created a new file: `Cargo.lock`. From ae21b4f58154abf3837744c91dbe23821ef52f05 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Thu, 12 Mar 2015 18:09:52 -0400 Subject: [PATCH 07/12] remove mention of specialization from `Hash` trait It is no longer possible to specialize on the `Hasher` because it moved to a method-level type parameter. --- src/libcore/hash/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 4b545435ea1..fdc0020dfcd 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -70,9 +70,7 @@ mod sip; /// A hashable type. /// /// The `H` type parameter is an abstract hash state that is used by the `Hash` -/// to compute the hash. Specific implementations of this trait may specialize -/// for particular instances of `H` in order to be able to optimize the hashing -/// behavior. +/// to compute the hash. #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { /// Feeds this value into the state given, updating the hasher as necessary. From ebcb1dca433e5473431b519cfce4815dd27014e0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 12 Mar 2015 17:37:51 -0700 Subject: [PATCH 08/12] Fix naming of beta artifacts again --- mk/main.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mk/main.mk b/mk/main.mk index 4bfc65ad843..ad9d0d0ca5e 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -30,8 +30,8 @@ CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM) CFG_DISABLE_UNSTABLE_FEATURES=1 endif ifeq ($(CFG_RELEASE_CHANNEL),beta) -CFG_RELEASE=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION) -CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION) +CFG_RELEASE=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION) +CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION) CFG_DISABLE_UNSTABLE_FEATURES=1 endif ifeq ($(CFG_RELEASE_CHANNEL),nightly) From 0942803f502d164883294e29238e3ac4822867ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 13 Mar 2015 03:19:30 +0100 Subject: [PATCH 09/12] Add an "allocator" attribute to mark functions as allocators When this attribute is applied to a function, its return value gets the noalias attribute, which is how you tell LLVM that the function returns a "new" pointer that doesn't alias anything accessible to the caller, i.e. it acts like a memory allocator. Plain malloc doesn't need this attribute because LLVM already knows about malloc and adds the attribute itself. --- src/liballoc/heap.rs | 1 + src/liballoc/lib.rs | 1 + src/librustc_trans/trans/base.rs | 15 +++++++++++---- src/librustc_trans/trans/foreign.rs | 4 ++-- src/libsyntax/feature_gate.rs | 3 +++ 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 3b93171386a..f9936b7a16a 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -198,6 +198,7 @@ mod imp { extern {} extern { + #[allocator] fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void; fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5c9a42a8a71..34c0686fe37 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -69,6 +69,7 @@ #![feature(no_std)] #![no_std] +#![feature(allocator)] #![feature(lang_items, unsafe_destructor)] #![feature(box_syntax)] #![feature(optin_builtin_traits)] diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f49905613d2..83f31956815 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -33,7 +33,7 @@ use super::ModuleTranslation; use back::link::{mangle_exported_name}; use back::{link, abi}; use lint; -use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; +use llvm::{AttrHelper, BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; @@ -456,6 +456,9 @@ pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: Val llvm::FunctionIndex as c_uint, llvm::ColdAttribute as uint64_t) }, + "allocator" => { + llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); + } _ => used = false, } if used { @@ -903,8 +906,10 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.sess().bug("unexpected intrinsic in trans_external_path") } _ => { - foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, - &name[..]) + let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]); + let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); + set_llvm_fn_attrs(ccx, &attrs, llfn); + llfn } } } @@ -2848,7 +2853,9 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let abi = ccx.tcx().map.get_foreign_abi(id); let ty = ty::node_id_to_type(ccx.tcx(), ni.id); let name = foreign::link_name(&*ni); - foreign::register_foreign_item_fn(ccx, abi, ty, &name) + let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); + set_llvm_fn_attrs(ccx, &ni.attrs, llfn); + llfn } ast::ForeignItemStatic(..) => { foreign::register_static(ccx, &*ni) diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index b0383e355e4..dfc7e7f604f 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -470,8 +470,8 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { "foreign fn's sty isn't a bare_fn_ty?") } - register_foreign_item_fn(ccx, abi, ty, - &lname); + let llfn = register_foreign_item_fn(ccx, abi, ty, &lname); + base::set_llvm_fn_attrs(ccx, &foreign_item.attrs, llfn); // Unlike for other items, we shouldn't call // `base::update_linkage` here. Foreign items have // special linkage requirements, which are handled diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c3bac0cf57c..0a9980c8925 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -83,6 +83,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("box_syntax", "1.0.0", Active), ("on_unimplemented", "1.0.0", Active), ("simd_ffi", "1.0.0", Active), + ("allocator", "1.0.0", Active), ("if_let", "1.0.0", Accepted), ("while_let", "1.0.0", Accepted), @@ -230,6 +231,8 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("rustc_on_unimplemented", Gated("on_unimplemented", "the `#[rustc_on_unimplemented]` attribute \ is an experimental feature")), + ("allocator", Gated("allocator", + "the `#[allocator]` attribute is an experimental feature")), ("rustc_variance", Gated("rustc_attrs", "the `#[rustc_variance]` attribute \ is an experimental feature")), From 4e25765aa2b973a4dda1f61dd8b5f167752e74ef Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 12 Mar 2015 19:15:52 -0700 Subject: [PATCH 10/12] rustdoc: Fix ICE with cross-crate default impls This adds a special code path for impls which are listed as default impls to ensure that they're loaded correctly. --- src/librustc/metadata/csearch.rs | 5 +++ src/librustc/metadata/decoder.rs | 7 +++- src/librustdoc/clean/inline.rs | 41 ++++++++++++++----- src/librustdoc/clean/mod.rs | 27 ++++++++++++ src/librustdoc/doctree.rs | 2 + src/librustdoc/html/item_type.rs | 1 + src/librustdoc/passes.rs | 2 +- src/librustdoc/visit_ast.rs | 4 +- .../run-make/rustdoc-default-impl/Makefile | 5 +++ src/test/run-make/rustdoc-default-impl/bar.rs | 17 ++++++++ src/test/run-make/rustdoc-default-impl/foo.rs | 33 +++++++++++++++ 11 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 src/test/run-make/rustdoc-default-impl/Makefile create mode 100644 src/test/run-make/rustdoc-default-impl/bar.rs create mode 100644 src/test/run-make/rustdoc-default-impl/foo.rs diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index ed5783c8dba..ca8ae83ab80 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -411,3 +411,8 @@ pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: ast::DefId) -> let cdata = cstore.get_crate_data(trait_def_id.krate); decoder::is_defaulted_trait(&*cdata, trait_def_id.node) } + +pub fn is_default_impl(cstore: &cstore::CStore, impl_did: ast::DefId) -> bool { + let cdata = cstore.get_crate_data(impl_did.krate); + decoder::is_default_impl(&*cdata, impl_did.node) +} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index dbbc17c018a..c0bad80ab59 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1537,13 +1537,18 @@ pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool { } } -pub fn is_defaulted_trait<'tcx>(cdata: Cmd, trait_id: ast::NodeId) -> bool { +pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool { let trait_doc = lookup_item(trait_id, cdata.data()); assert!(item_family(trait_doc) == Family::Trait); let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait); reader::doc_as_u8(defaulted_doc) != 0 } +pub fn is_default_impl(cdata: Cmd, impl_id: ast::NodeId) -> bool { + let impl_doc = lookup_item(impl_id, cdata.data()); + item_family(impl_doc) == Family::DefaultImpl +} + pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { let crate_doc = rbml::Doc::new(metadata); let cm_doc = reader::get_doc(crate_doc, tag_codemap); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9f7b68f38fa..aa17bf20d74 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -259,26 +259,43 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt, impls.into_iter().filter_map(|a| a).collect() } -fn build_impl(cx: &DocContext, tcx: &ty::ctxt, +fn build_impl(cx: &DocContext, + tcx: &ty::ctxt, did: ast::DefId) -> Option { if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) { return None } + let attrs = load_attrs(cx, tcx, did); let associated_trait = csearch::get_impl_trait(tcx, did); - // If this is an impl for a #[doc(hidden)] trait, be sure to not inline it. - match associated_trait { - Some(ref t) => { - let trait_attrs = load_attrs(cx, tcx, t.def_id); - if trait_attrs.iter().any(|a| is_doc_hidden(a)) { - return None - } + if let Some(ref t) = associated_trait { + // If this is an impl for a #[doc(hidden)] trait, be sure to not inline + let trait_attrs = load_attrs(cx, tcx, t.def_id); + if trait_attrs.iter().any(|a| is_doc_hidden(a)) { + return None } - None => {} } - let attrs = load_attrs(cx, tcx, did); - let ty = ty::lookup_item_type(tcx, did); + // If this is a defaulted impl, then bail out early here + if csearch::is_default_impl(&tcx.sess.cstore, did) { + return Some(clean::Item { + inner: clean::DefaultImplItem(clean::DefaultImpl { + // FIXME: this should be decoded + unsafety: ast::Unsafety::Normal, + trait_: match associated_trait.as_ref().unwrap().clean(cx) { + clean::TraitBound(polyt, _) => polyt.trait_, + clean::RegionBound(..) => unreachable!(), + }, + }), + source: clean::Span::empty(), + name: None, + attrs: attrs, + visibility: Some(ast::Inherited), + stability: stability::lookup(tcx, did).clean(cx), + def_id: did, + }); + } + let predicates = ty::lookup_predicates(tcx, did); let trait_items = csearch::get_impl_items(&tcx.sess.cstore, did) .iter() @@ -330,8 +347,10 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, } }).collect(); let polarity = csearch::get_impl_polarity(tcx, did); + let ty = ty::lookup_item_type(tcx, did); return Some(clean::Item { inner: clean::ImplItem(clean::Impl { + unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded derived: clean::detect_derived(&attrs), trait_: associated_trait.clean(cx).map(|bound| { match bound { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e91e95961c5..421549f8b7e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -337,6 +337,7 @@ pub enum ItemEnum { MacroItem(Macro), PrimitiveItem(PrimitiveType), AssociatedTypeItem(Vec, Option), + DefaultImplItem(DefaultImpl), } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] @@ -367,6 +368,7 @@ impl Clean for doctree::Module { items.extend(self.traits.iter().map(|x| x.clean(cx))); items.extend(self.impls.iter().map(|x| x.clean(cx))); items.extend(self.macros.iter().map(|x| x.clean(cx))); + items.extend(self.def_traits.iter().map(|x| x.clean(cx))); // determine if we should display the inner contents or // the outer `mod` item for the source code. @@ -2079,6 +2081,7 @@ impl Clean for ast::ImplPolarity { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Impl { + pub unsafety: ast::Unsafety, pub generics: Generics, pub trait_: Option, pub for_: Type, @@ -2101,6 +2104,7 @@ impl Clean for doctree::Impl { visibility: self.vis.clean(cx), stability: self.stab.clean(cx), inner: ImplItem(Impl { + unsafety: self.unsafety, generics: self.generics.clean(cx), trait_: self.trait_.clean(cx), for_: self.for_.clean(cx), @@ -2112,6 +2116,29 @@ impl Clean for doctree::Impl { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct DefaultImpl { + pub unsafety: ast::Unsafety, + pub trait_: Type, +} + +impl Clean for doctree::DefaultImpl { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: None, + attrs: self.attrs.clean(cx), + source: self.whence.clean(cx), + def_id: ast_util::local_def(self.id), + visibility: Some(ast::Public), + stability: None, + inner: DefaultImplItem(DefaultImpl { + unsafety: self.unsafety, + trait_: self.trait_.clean(cx), + }), + } + } +} + impl Clean for doctree::ExternCrate { fn clean(&self, cx: &DocContext) -> Item { Item { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 5a4deaa2e72..c6d8b9428c5 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -202,6 +202,8 @@ pub struct DefaultImpl { pub unsafety: ast::Unsafety, pub trait_: ast::TraitRef, pub id: ast::NodeId, + pub attrs: Vec, + pub whence: Span, } pub struct Macro { diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 356be2ffeb0..1d63f01be52 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -64,6 +64,7 @@ impl ItemType { clean::MacroItem(..) => ItemType::Macro, clean::PrimitiveItem(..) => ItemType::Primitive, clean::AssociatedTypeItem(..) => ItemType::AssociatedType, + clean::DefaultImplItem(..) => ItemType::Impl, } } diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 722f14fa6d4..953b442bb3c 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -176,7 +176,7 @@ impl<'a> fold::DocFolder for Stripper<'a> { return None; } } - clean::ImplItem(..) => {} + clean::DefaultImplItem(..) | clean::ImplItem(..) => {} // tymethods/macros have no control over privacy clean::MacroItem(..) | clean::TyMethodItem(..) => {} diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 3e998166397..d53954b29b5 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -362,7 +362,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let i = DefaultImpl { unsafety: unsafety, trait_: trait_ref.clone(), - id: item.id + id: item.id, + attrs: item.attrs.clone(), + whence: item.span, }; om.def_traits.push(i); } diff --git a/src/test/run-make/rustdoc-default-impl/Makefile b/src/test/run-make/rustdoc-default-impl/Makefile new file mode 100644 index 00000000000..338cf9d2053 --- /dev/null +++ b/src/test/run-make/rustdoc-default-impl/Makefile @@ -0,0 +1,5 @@ +-include ../tools.mk + +all: foo.rs bar.rs + $(RUSTC) foo.rs --crate-type lib + $(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc bar.rs -L $(TMPDIR) diff --git a/src/test/run-make/rustdoc-default-impl/bar.rs b/src/test/run-make/rustdoc-default-impl/bar.rs new file mode 100644 index 00000000000..c9fae80d858 --- /dev/null +++ b/src/test/run-make/rustdoc-default-impl/bar.rs @@ -0,0 +1,17 @@ +// 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. + +extern crate foo; + +pub use foo::bar; + +pub fn wut() { +} + diff --git a/src/test/run-make/rustdoc-default-impl/foo.rs b/src/test/run-make/rustdoc-default-impl/foo.rs new file mode 100644 index 00000000000..08f3bd10e74 --- /dev/null +++ b/src/test/run-make/rustdoc-default-impl/foo.rs @@ -0,0 +1,33 @@ +// 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. + +pub mod bar { + use std::marker; + + pub trait Bar: marker::MarkerTrait + 'static {} + + impl Bar for .. {} + + pub trait Foo { + fn foo(&self) {} + } + + impl Foo { + pub fn test(&self) {} + } + + pub struct TypeId; + + impl TypeId { + pub fn of() -> TypeId { + panic!() + } + } +} From 825f49a89ab27e6c394cd9a7a7c59097baa8ea33 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 13 Mar 2015 19:51:09 +0530 Subject: [PATCH 11/12] Fix def -> PathResolution --- src/librustc/middle/pat_util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 7f3b00eb3e6..eca3296e65c 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -165,7 +165,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &ast::Pat) -> Vec { ast::PatIdent(_, _, None) | ast::PatStruct(..) => { match dm.borrow().get(&p.id) { - Some(&DefVariant(_, id, _)) => { + Some(&PathResolution {base_def: DefVariant(_, id, _), ..}) => { variants.push(id.node); } _ => () From 40b64645fecbee4e11da1ea4328c1b1ab4b9b8a0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 13 Mar 2015 19:52:18 +0530 Subject: [PATCH 12/12] rm unused import --- src/libsyntax/parse/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index fae305f9551..f542246705c 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -754,7 +754,6 @@ pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> mod test { use super::*; use std::rc::Rc; - use serialize::json; use codemap::{Span, BytePos, Pos, Spanned, NO_EXPANSION}; use owned_slice::OwnedSlice; use ast;