Skip to content

Rollup of 8 pull requests #63471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
Aug 11, 2019
Merged
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
740f8db
Add FIXME-s that some types should be transparent
MikailBag Jun 19, 2019
03e95ae
Miri shouldn't look at types
RalfJung Aug 10, 2019
62f1e8a
fix test
RalfJung Aug 10, 2019
440a5c8
rename RUST_CTFE_BACKTRACE to RUSTC_CTFE_BACKTRACE
RalfJung Aug 10, 2019
d809d6e
Derive Debug for CrateInfo
bjorn3 Aug 10, 2019
93839c3
Add an example to show how to insert item to a sorted vec
tesuji Aug 10, 2019
30ba4bd
Use Result::unwrap_or_else instead of matching
tesuji Aug 10, 2019
da6fbb1
add basic lint testing for misuse of mem::zeroed and mem::uninitialized
RalfJung Aug 6, 2019
ca1e94b
warn for more cases
RalfJung Aug 7, 2019
fbd5613
fix a comment
RalfJung Aug 7, 2019
8e6fbbe
add tuple_fields convenience method and use it in a few places
RalfJung Aug 7, 2019
4b062a1
note a FIXME
RalfJung Aug 7, 2019
3972d05
proper doc comment for 'recovered' field of variant
RalfJung Aug 7, 2019
c5a6356
allow the lint if a few UB-demonstrating doc tests
RalfJung Aug 7, 2019
5c77a17
note down some more future plans
RalfJung Aug 7, 2019
0930747
update clippy
RalfJung Aug 11, 2019
65ea7b7
rustdoc: Replace HirVec with slices in doctree
Mark-Simulacrum Aug 10, 2019
19c85a8
Move def_id_to_path to use site in visit_ast
Mark-Simulacrum Aug 10, 2019
00d7bc7
Remove crate_name from DocContext
Mark-Simulacrum Aug 10, 2019
8f80a8d
Use entry API in store_path
Mark-Simulacrum Aug 10, 2019
c574810
Remove ReentrantMutex
Mark-Simulacrum Aug 10, 2019
6be2857
Replace Arc with Rc around external_traits
Mark-Simulacrum Aug 10, 2019
0031951
Store typed Passes
Mark-Simulacrum Aug 10, 2019
0347480
Don't store all traits in DocContext
Mark-Simulacrum Aug 10, 2019
eea2f87
Use a HashSet instead of Vec
Mark-Simulacrum Aug 10, 2019
ade8b02
Remove unnecessary channel
Mark-Simulacrum Aug 10, 2019
dbad77f
Remove thread-local for playground config
Mark-Simulacrum Aug 10, 2019
c250b5f
Remove fmt::Display impls on Markdown structs
Mark-Simulacrum Aug 10, 2019
1aa0964
Drop RefCell from IdMap in markdown rendering
Mark-Simulacrum Aug 10, 2019
3b8a24d
Reduce nesting in externalfiles implementation
Mark-Simulacrum Aug 10, 2019
b204232
Derive Debug for NativeLibrary and NativeLibraryKind
bjorn3 Aug 11, 2019
43de341
Copy ty::Instance instead of passing by reference
Mark-Simulacrum Aug 11, 2019
8862977
Rollup merge of #61969 - MikailBag:master, r=Centril
Mark-Simulacrum Aug 11, 2019
061245e
Rollup merge of #63346 - RalfJung:zeroed-lint, r=eddyb
Mark-Simulacrum Aug 11, 2019
24a8337
Rollup merge of #63433 - RalfJung:miri-call, r=oli-obk
Mark-Simulacrum Aug 11, 2019
8122a01
Rollup merge of #63440 - RalfJung:ctfe-backtrace, r=oli-obk
Mark-Simulacrum Aug 11, 2019
c805a38
Rollup merge of #63441 - bjorn3:patch-1, r=Mark-Simulacrum
Mark-Simulacrum Aug 11, 2019
e16b12f
Rollup merge of #63442 - lzutao:vec-bin-search-insert, r=Mark-Simulacrum
Mark-Simulacrum Aug 11, 2019
86ceab4
Rollup merge of #63453 - Mark-Simulacrum:rustdoc-clean-2, r=Guillaume…
Mark-Simulacrum Aug 11, 2019
4229dc3
Rollup merge of #63464 - Mark-Simulacrum:deref-instance, r=eddyb
Mark-Simulacrum Aug 11, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
@@ -3252,7 +3252,6 @@ name = "rustdoc"
version = "0.0.0"
dependencies = [
"minifier 0.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
3 changes: 3 additions & 0 deletions src/libcore/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ use crate::mem::ManuallyDrop;
/// ever gets used to access memory:
///
/// ```rust,no_run
/// # #![allow(invalid_value)]
/// use std::mem::{self, MaybeUninit};
///
/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
@@ -27,6 +28,7 @@ use crate::mem::ManuallyDrop;
/// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior:
///
/// ```rust,no_run
/// # #![allow(invalid_value)]
/// use std::mem::{self, MaybeUninit};
///
/// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior!
@@ -40,6 +42,7 @@ use crate::mem::ManuallyDrop;
/// which otherwise can hold any *fixed* bit pattern:
///
/// ```rust,no_run
/// # #![allow(invalid_value)]
/// use std::mem::{self, MaybeUninit};
///
/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior!
3 changes: 2 additions & 1 deletion src/libcore/mem/mod.rs
Original file line number Diff line number Diff line change
@@ -445,7 +445,8 @@ pub const fn needs_drop<T>() -> bool {
///
/// *Incorrect* usage of this function: initializing a reference with zero.
///
/// ```no_run
/// ```rust,no_run
/// # #![allow(invalid_value)]
/// use std::mem;
///
/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior!
11 changes: 11 additions & 0 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
@@ -1364,6 +1364,17 @@ impl<T> [T] {
/// let r = s.binary_search(&1);
/// assert!(match r { Ok(1..=4) => true, _ => false, });
/// ```
///
/// If you want to insert an item to a sorted vector, while maintaining
/// sort order:
///
/// ```
/// let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
/// let num = 42;
/// let idx = s.binary_search(&num).unwrap_or_else(|x| x);
/// s.insert(idx, num);
/// assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn binary_search(&self, x: &T) -> Result<usize, usize>
where T: Ord
4 changes: 2 additions & 2 deletions src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@ pub enum LinkagePreference {
RequireStatic,
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash,
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
RustcEncodable, RustcDecodable, HashStable)]
pub enum NativeLibraryKind {
/// native static library (.a archive)
@@ -100,7 +100,7 @@ pub enum NativeLibraryKind {
NativeUnknown,
}

#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
pub struct NativeLibrary {
pub kind: NativeLibraryKind,
pub name: Option<Symbol>,
2 changes: 1 addition & 1 deletion src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
@@ -217,7 +217,7 @@ fn print_backtrace(backtrace: &mut Backtrace) {

impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self {
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {
// Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
Ok(ref val) if val != "0" => {
let mut backtrace = Backtrace::new_unresolved();
4 changes: 2 additions & 2 deletions src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
@@ -2518,7 +2518,7 @@ where
+ HasTyCtxt<'tcx>
+ HasParamEnv<'tcx>,
{
fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self;
fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self;
fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
fn new_internal(
@@ -2538,7 +2538,7 @@ where
+ HasTyCtxt<'tcx>
+ HasParamEnv<'tcx>,
{
fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self {
fn of_instance(cx: &C, instance: ty::Instance<'tcx>) -> Self {
let sig = instance.fn_sig(cx.tcx());
let sig = cx
.tcx()
7 changes: 5 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -1842,7 +1842,8 @@ pub struct VariantDef {
pub ctor_kind: CtorKind,
/// Flags of the variant (e.g. is field list non-exhaustive)?
flags: VariantFlags,
/// Recovered?
/// Variant is obtained as part of recovering from a syntactic error.
/// May be incomplete or bogus.
pub recovered: bool,
}

@@ -1949,7 +1950,7 @@ pub struct FieldDef {
pub struct AdtDef {
/// `DefId` of the struct, enum or union item.
pub did: DefId,
/// Variants of the ADT. If this is a struct or enum, then there will be a single variant.
/// Variants of the ADT. If this is a struct or union, then there will be a single variant.
pub variants: IndexVec<self::layout::VariantIdx, VariantDef>,
/// Flags of the ADT (e.g. is this a struct? is this non-exhaustive?)
flags: AdtFlags,
@@ -2565,6 +2566,8 @@ impl<'tcx> AdtDef {
}

impl<'tcx> FieldDef {
/// Returns the type of this field. The `subst` is typically obtained
/// via the second field of `TyKind::AdtDef`.
pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
tcx.type_of(self.did).subst(tcx, subst)
}
14 changes: 12 additions & 2 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
@@ -171,6 +171,7 @@ pub enum TyKind<'tcx> {
Never,

/// A tuple type. For example, `(i32, bool)`.
/// Use `TyS::tuple_fields` to iterate over the field types.
Tuple(SubstsRef<'tcx>),

/// The projection of an associated type. For example,
@@ -1723,8 +1724,8 @@ impl<'tcx> TyS<'tcx> {
})
})
}
ty::Tuple(tys) => tys.iter().any(|ty| {
ty.expect_ty().conservative_is_privately_uninhabited(tcx)
ty::Tuple(..) => self.tuple_fields().any(|ty| {
ty.conservative_is_privately_uninhabited(tcx)
}),
ty::Array(ty, len) => {
match len.try_eval_usize(tcx, ParamEnv::empty()) {
@@ -2103,6 +2104,15 @@ impl<'tcx> TyS<'tcx> {
}
}

/// Iterates over tuple fields.
/// Panics when called on anything but a tuple.
pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> {
match self.sty {
Tuple(substs) => substs.iter().map(|field| field.expect_ty()),
_ => bug!("tuple_fields called on non-tuple"),
}
}

/// If the type contains variants, returns the valid range of variant indices.
/// FIXME This requires the optimized MIR in the case of generators.
#[inline]
8 changes: 4 additions & 4 deletions src/librustc/ty/util.rs
Original file line number Diff line number Diff line change
@@ -845,15 +845,15 @@ impl<'tcx> ty::TyS<'tcx> {
ty: Ty<'tcx>,
) -> Representability {
match ty.sty {
Tuple(ref ts) => {
Tuple(..) => {
// Find non representable
fold_repr(ts.iter().map(|ty| {
fold_repr(ty.tuple_fields().map(|ty| {
is_type_structurally_recursive(
tcx,
sp,
seen,
representable_cache,
ty.expect_ty(),
ty,
)
}))
}
@@ -1095,7 +1095,7 @@ fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>
// state transformation pass
ty::Generator(..) => true,

ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).any(needs_drop),
ty::Tuple(..) => ty.tuple_fields().any(needs_drop),

// unions don't have destructors because of the child types,
// only if they manually implement `Drop` (handled above).
4 changes: 2 additions & 2 deletions src/librustc/ty/walk.rs
Original file line number Diff line number Diff line change
@@ -119,8 +119,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
ty::GeneratorWitness(ts) => {
stack.extend(ts.skip_binder().iter().cloned().rev());
}
ty::Tuple(ts) => {
stack.extend(ts.iter().map(|k| k.expect_ty()).rev());
ty::Tuple(..) => {
stack.extend(parent_ty.tuple_fields().rev());
}
ty::FnDef(_, substs) => {
stack.extend(substs.types().rev());
1 change: 1 addition & 0 deletions src/librustc_codegen_ssa/lib.rs
Original file line number Diff line number Diff line change
@@ -128,6 +128,7 @@ bitflags::bitflags! {
}

/// Misc info we load from metadata to persist beyond the tcx.
#[derive(Debug)]
pub struct CrateInfo {
pub panic_runtime: Option<CrateNum>,
pub compiler_builtins: Option<CrateNum>,
6 changes: 3 additions & 3 deletions src/librustc_codegen_ssa/mir/block.rs
Original file line number Diff line number Diff line change
@@ -337,7 +337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
_ => {
(bx.get_fn(drop_fn),
FnType::of_instance(&bx, &drop_fn))
FnType::of_instance(&bx, drop_fn))
}
};
helper.do_call(self, &mut bx, fn_ty, drop_fn, args,
@@ -435,7 +435,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Obtain the panic entry point.
let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
let instance = ty::Instance::mono(bx.tcx(), def_id);
let fn_ty = FnType::of_instance(&bx, &instance);
let fn_ty = FnType::of_instance(&bx, instance);
let llfn = bx.get_fn(instance);

// Codegen the actual panic invoke/call.
@@ -552,7 +552,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let def_id =
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
let instance = ty::Instance::mono(bx.tcx(), def_id);
let fn_ty = FnType::of_instance(&bx, &instance);
let fn_ty = FnType::of_instance(&bx, instance);
let llfn = bx.get_fn(instance);

// Codegen the actual panic invoke/call.
91 changes: 90 additions & 1 deletion src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@

use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::{self, Ty, TyCtxt, layout::VariantIdx};
use rustc::{lint, util};
use hir::Node;
use util::nodemap::HirIdSet;
@@ -1862,3 +1862,92 @@ impl EarlyLintPass for IncompleteFeatures {
});
}
}

declare_lint! {
pub INVALID_VALUE,
Warn,
"an invalid value is being created (such as a NULL reference)"
}

declare_lint_pass!(InvalidValue => [INVALID_VALUE]);

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) {

const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];

/// Return `false` only if we are sure this type does *not*
/// allow zero initialization.
fn ty_maybe_allows_zero_init<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
use rustc::ty::TyKind::*;
match ty.sty {
// Primitive types that don't like 0 as a value.
Ref(..) | FnPtr(..) | Never => false,
Adt(..) if ty.is_box() => false,
// Recurse for some compound types.
Adt(adt_def, substs) if !adt_def.is_union() => {
match adt_def.variants.len() {
0 => false, // Uninhabited enum!
1 => {
// Struct, or enum with exactly one variant.
// Proceed recursively, check all fields.
let variant = &adt_def.variants[VariantIdx::from_u32(0)];
variant.fields.iter().all(|field| {
ty_maybe_allows_zero_init(
tcx,
field.ty(tcx, substs),
)
})
}
_ => true, // Conservative fallback for multi-variant enum.
}
}
Tuple(..) => {
// Proceed recursively, check all fields.
ty.tuple_fields().all(|field| ty_maybe_allows_zero_init(tcx, field))
}
// FIXME: Would be nice to also warn for `NonNull`/`NonZero*`.
// FIXME: *Only for `mem::uninitialized`*, we could also warn for `bool`,
// `char`, and any multivariant enum.
// Conservative fallback.
_ => true,
}
}

if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
if cx.match_def_path(def_id, &ZEROED_PATH) ||
cx.match_def_path(def_id, &UININIT_PATH)
{
// This conjures an instance of a type out of nothing,
// using zeroed or uninitialized memory.
// We are extremely conservative with what we warn about.
let conjured_ty = cx.tables.expr_ty(expr);

if !ty_maybe_allows_zero_init(cx.tcx, conjured_ty) {
cx.struct_span_lint(
INVALID_VALUE,
expr.span,
&format!(
"the type `{}` does not permit {}",
conjured_ty,
if cx.match_def_path(def_id, &ZEROED_PATH) {
"zero-initialization"
} else {
"being left uninitialized"
}
),
)
.note("this means that this code causes undefined behavior \
when executed")
.help("use `MaybeUninit` instead")
.emit();
}
}
}
}
}
}
}
1 change: 1 addition & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
@@ -177,6 +177,7 @@ macro_rules! late_lint_mod_passes {
UnreachablePub: UnreachablePub,

ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
InvalidValue: InvalidValue,
]);
)
}
10 changes: 7 additions & 3 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
@@ -385,15 +385,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
local: mir::Local,
layout: Option<TyLayout<'tcx>>,
) -> InterpResult<'tcx, TyLayout<'tcx>> {
match frame.locals[local].layout.get() {
// `const_prop` runs into this with an invalid (empty) frame, so we
// have to support that case (mostly by skipping all caching).
match frame.locals.get(local).and_then(|state| state.layout.get()) {
None => {
let layout = crate::interpret::operand::from_known_layout(layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?;
self.layout_of(local_ty)
})?;
// Layouts of locals are requested a lot, so we cache them.
frame.locals[local].layout.set(Some(layout));
if let Some(state) = frame.locals.get(local) {
// Layouts of locals are requested a lot, so we cache them.
state.layout.set(Some(layout));
}
Ok(layout)
}
Some(layout) => Ok(layout),
4 changes: 2 additions & 2 deletions src/librustc_mir/interpret/snapshot.rs
Original file line number Diff line number Diff line change
@@ -304,7 +304,7 @@ impl_stable_hash_for!(enum crate::interpret::eval_context::StackPopCleanup {

#[derive(Eq, PartialEq)]
struct FrameSnapshot<'a, 'tcx> {
instance: &'a ty::Instance<'tcx>,
instance: ty::Instance<'tcx>,
span: Span,
return_to_block: &'a StackPopCleanup,
return_place: Option<Place<(), AllocIdSnapshot<'a>>>,
@@ -344,7 +344,7 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
} = self;

FrameSnapshot {
instance,
instance: *instance,
span: *span,
return_to_block,
block,
8 changes: 5 additions & 3 deletions src/librustc_mir/interpret/terminator.rs
Original file line number Diff line number Diff line change
@@ -405,9 +405,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
} else {
let local = mir::RETURN_PLACE;
let ty = self.frame().body.local_decls[local].ty;
if !self.tcx.is_ty_uninhabited_from_any_module(ty) {
throw_unsup!(FunctionRetMismatch(self.tcx.types.never, ty))
let callee_layout = self.layout_of_local(self.frame(), local, None)?;
if !callee_layout.abi.is_uninhabited() {
throw_unsup!(FunctionRetMismatch(
self.tcx.types.never, callee_layout.ty
))
}
}
Ok(())
2 changes: 1 addition & 1 deletion src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
@@ -324,7 +324,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -
substs.upvar_tys(def_id, tcx)
)
}
ty::Tuple(tys) => builder.tuple_like_shim(dest, src, tys.iter().map(|k| k.expect_ty())),
ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
_ => {
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
}
4 changes: 2 additions & 2 deletions src/librustc_mir/util/elaborate_drops.rs
Original file line number Diff line number Diff line change
@@ -804,8 +804,8 @@ where
let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect();
self.open_drop_for_tuple(&tys)
}
ty::Tuple(tys) => {
let tys: Vec<_> = tys.iter().map(|k| k.expect_ty()).collect();
ty::Tuple(..) => {
let tys: Vec<_> = ty.tuple_fields().collect();
self.open_drop_for_tuple(&tys)
}
ty::Adt(def, substs) => {
1 change: 0 additions & 1 deletion src/librustdoc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -13,4 +13,3 @@ pulldown-cmark = { version = "0.5.3", default-features = false }
minifier = "0.0.33"
rayon = { version = "0.2.0", package = "rustc-rayon" }
tempfile = "3"
parking_lot = "0.7"
3 changes: 2 additions & 1 deletion src/librustdoc/clean/blanket_impl.rs
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ use rustc::traits;
use rustc::ty::ToPredicate;
use rustc::ty::subst::Subst;
use rustc::infer::InferOk;
use rustc::hir::def_id::LOCAL_CRATE;
use syntax_pos::DUMMY_SP;

use super::*;
@@ -27,7 +28,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {

debug!("get_blanket_impls({:?})", ty);
let mut impls = Vec::new();
for &trait_def_id in self.cx.all_traits.iter() {
for &trait_def_id in self.cx.tcx.all_traits(LOCAL_CRATE).iter() {
if !self.cx.renderinfo.borrow().access_levels.is_public(trait_def_id) ||
self.cx.generated_synthetics
.borrow_mut()
17 changes: 5 additions & 12 deletions src/librustdoc/clean/inline.rs
Original file line number Diff line number Diff line change
@@ -163,10 +163,7 @@ pub fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> {
/// These names are used later on by HTML rendering to generate things like
/// source links back to the original item.
pub fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKind) {
let mut crate_name = cx.tcx.crate_name(did.krate).to_string();
if did.is_local() {
crate_name = cx.crate_name.clone().unwrap_or(crate_name);
}
let crate_name = cx.tcx.crate_name(did.krate).to_string();

let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
// extern blocks have an empty name
@@ -577,22 +574,18 @@ pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) {
}

{
let external_traits = cx.external_traits.lock();
if external_traits.borrow().contains_key(&did) ||
if cx.external_traits.borrow().contains_key(&did) ||
cx.active_extern_traits.borrow().contains(&did)
{
return;
}
}

cx.active_extern_traits.borrow_mut().push(did);
cx.active_extern_traits.borrow_mut().insert(did);

debug!("record_extern_trait: {:?}", did);
let trait_ = build_external_trait(cx, did);

{
let external_traits = cx.external_traits.lock();
external_traits.borrow_mut().insert(did, trait_);
}
cx.active_extern_traits.borrow_mut().remove_item(&did);
cx.external_traits.borrow_mut().insert(did, trait_);
cx.active_extern_traits.borrow_mut().remove(&did);
}
26 changes: 4 additions & 22 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
@@ -39,14 +39,12 @@ use std::fmt;
use std::hash::{Hash, Hasher};
use std::default::Default;
use std::{mem, slice, vec};
use std::iter::{FromIterator, once};
use std::iter::FromIterator;
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::Arc;
use std::u32;

use parking_lot::ReentrantMutex;

use crate::core::{self, DocContext};
use crate::doctree;
use crate::html::render::{cache, ExternalLocation};
@@ -133,8 +131,9 @@ pub struct Crate {
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
// These are later on moved into `CACHEKEY`, leaving the map empty.
// Only here so that they can be filtered through the rustdoc passes.
pub external_traits: Arc<ReentrantMutex<RefCell<FxHashMap<DefId, Trait>>>>,
pub external_traits: Rc<RefCell<FxHashMap<DefId, Trait>>>,
pub masked_crates: FxHashSet<CrateNum>,
pub collapsed: bool,
}

impl Clean<Crate> for hir::Crate {
@@ -223,6 +222,7 @@ impl Clean<Crate> for hir::Crate {
primitives,
external_traits: cx.external_traits.clone(),
masked_crates,
collapsed: false,
}
}
}
@@ -4398,24 +4398,6 @@ impl Clean<TypeBindingKind> for hir::TypeBindingKind {
}
}

pub fn def_id_to_path(
cx: &DocContext<'_>,
did: DefId,
name: Option<String>
) -> Vec<String> {
let crate_name = name.unwrap_or_else(|| cx.tcx.crate_name(did.krate).to_string());
let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
// extern blocks have an empty name
let s = elem.data.to_string();
if !s.is_empty() {
Some(s)
} else {
None
}
});
once(crate_name).chain(relative).collect()
}

pub fn enter_impl_trait<F, R>(cx: &DocContext<'_>, f: F) -> R
where
F: FnOnce() -> R,
18 changes: 9 additions & 9 deletions src/librustdoc/config.rs
Original file line number Diff line number Diff line change
@@ -220,22 +220,22 @@ impl Options {
println!("{:>20} - {}", pass.name, pass.description);
}
println!("\nDefault passes for rustdoc:");
for &name in passes::DEFAULT_PASSES {
println!("{:>20}", name);
for pass in passes::DEFAULT_PASSES {
println!("{:>20}", pass.name);
}
println!("\nPasses run with `--document-private-items`:");
for &name in passes::DEFAULT_PRIVATE_PASSES {
println!("{:>20}", name);
for pass in passes::DEFAULT_PRIVATE_PASSES {
println!("{:>20}", pass.name);
}

if nightly_options::is_nightly_build() {
println!("\nPasses run with `--show-coverage`:");
for &name in passes::DEFAULT_COVERAGE_PASSES {
println!("{:>20}", name);
for pass in passes::DEFAULT_COVERAGE_PASSES {
println!("{:>20}", pass.name);
}
println!("\nPasses run with `--show-coverage --document-private-items`:");
for &name in passes::PRIVATE_COVERAGE_PASSES {
println!("{:>20}", name);
for pass in passes::PRIVATE_COVERAGE_PASSES {
println!("{:>20}", pass.name);
}
}

@@ -378,7 +378,7 @@ impl Options {
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
&matches.opt_strs("markdown-after-content"),
&diag, &mut id_map, edition) {
&diag, &mut id_map, edition, &None) {
Some(eh) => eh,
None => return Err(3),
};
47 changes: 20 additions & 27 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
@@ -22,12 +22,10 @@ use syntax::json::JsonEmitter;
use syntax::symbol::sym;
use errors;
use errors::emitter::{Emitter, EmitterWriter};
use parking_lot::ReentrantMutex;

use std::cell::RefCell;
use std::mem;
use rustc_data_structures::sync::{self, Lrc};
use std::sync::Arc;
use std::rc::Rc;

use crate::config::{Options as RustdocOptions, RenderOptions};
@@ -46,16 +44,14 @@ pub struct DocContext<'tcx> {

pub tcx: TyCtxt<'tcx>,
pub resolver: Rc<RefCell<interface::BoxedResolver>>,
/// The stack of module NodeIds up till this point
pub crate_name: Option<String>,
pub cstore: Lrc<CStore>,
/// Later on moved into `html::render::CACHE_KEY`
pub renderinfo: RefCell<RenderInfo>,
/// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
pub external_traits: Arc<ReentrantMutex<RefCell<FxHashMap<DefId, clean::Trait>>>>,
pub external_traits: Rc<RefCell<FxHashMap<DefId, clean::Trait>>>,
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
/// the same time.
pub active_extern_traits: RefCell<Vec<DefId>>,
pub active_extern_traits: RefCell<FxHashSet<DefId>>,
// The current set of type and lifetime substitutions,
// for expanding type aliases at the HIR level:

@@ -72,7 +68,6 @@ pub struct DocContext<'tcx> {
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
// FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
pub generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
pub all_traits: Vec<DefId>,
pub auto_traits: Vec<DefId>,
}

@@ -227,7 +222,7 @@ pub fn new_handler(error_format: ErrorOutputType,
)
}

pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions, Vec<String>) {
pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions) {
// Parse, resolve, and typecheck the given crate.

let RustdocOptions {
@@ -332,7 +327,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
file_loader: None,
diagnostic_output: DiagnosticOutput::Default,
stderr: None,
crate_name: crate_name.clone(),
crate_name,
lint_caps,
};

@@ -368,11 +363,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
let mut renderinfo = RenderInfo::default();
renderinfo.access_levels = access_levels;

let all_traits = tcx.all_traits(LOCAL_CRATE).to_vec();
let ctxt = DocContext {
tcx,
resolver,
crate_name,
cstore: compiler.cstore().clone(),
external_traits: Default::default(),
active_extern_traits: Default::default(),
@@ -384,10 +377,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
fake_def_ids: Default::default(),
all_fake_def_ids: Default::default(),
generated_synthetics: Default::default(),
auto_traits: all_traits.iter().cloned().filter(|trait_def_id| {
auto_traits: tcx.all_traits(LOCAL_CRATE).iter().cloned().filter(|trait_def_id| {
tcx.trait_is_auto(*trait_def_id)
}).collect(),
all_traits,
};
debug!("crate: {:?}", tcx.hir().krate());

@@ -432,8 +424,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
},
_ => continue,
};
for p in value.as_str().split_whitespace() {
sink.push(p.to_string());
for name in value.as_str().split_whitespace() {
sink.push(name.to_string());
}
}

@@ -444,25 +436,26 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
}
}

let mut passes: Vec<String> =
passes::defaults(default_passes).iter().map(|p| p.to_string()).collect();
passes.extend(manual_passes);
let passes = passes::defaults(default_passes).iter().chain(manual_passes.into_iter()
.flat_map(|name| {
if let Some(pass) = passes::find_pass(&name) {
Some(pass)
} else {
error!("unknown pass {}, skipping", name);
None
}
}));

info!("Executing passes");

for pass_name in &passes {
match passes::find_pass(pass_name).map(|p| p.pass) {
Some(pass) => {
debug!("running pass {}", pass_name);
krate = pass(krate, &ctxt);
}
None => error!("unknown pass {}, skipping", *pass_name),
}
for pass in passes {
debug!("running pass {}", pass.name);
krate = (pass.pass)(krate, &ctxt);
}

ctxt.sess().abort_if_errors();

(krate, ctxt.renderinfo.into_inner(), render_options, passes)
(krate, ctxt.renderinfo.into_inner(), render_options)
})
})
}
42 changes: 21 additions & 21 deletions src/librustdoc/doctree.rs
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ use rustc::hir::ptr::P;

pub struct Module<'hir> {
pub name: Option<Name>,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub where_outer: Span,
pub where_inner: Span,
pub extern_crates: Vec<ExternCrate<'hir>>,
@@ -41,7 +41,7 @@ pub struct Module<'hir> {
impl Module<'hir> {
pub fn new(
name: Option<Name>,
attrs: &'hir hir::HirVec<ast::Attribute>,
attrs: &'hir [ast::Attribute],
vis: &'hir hir::Visibility,
) -> Module<'hir> {
Module {
@@ -89,7 +89,7 @@ pub struct Struct<'hir> {
pub struct_type: StructType,
pub name: Name,
pub generics: &'hir hir::Generics,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub fields: &'hir [hir::StructField],
pub whence: Span,
}
@@ -100,7 +100,7 @@ pub struct Union<'hir> {
pub struct_type: StructType,
pub name: Name,
pub generics: &'hir hir::Generics,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub fields: &'hir [hir::StructField],
pub whence: Span,
}
@@ -109,7 +109,7 @@ pub struct Enum<'hir> {
pub vis: &'hir hir::Visibility,
pub variants: Vec<Variant<'hir>>,
pub generics: &'hir hir::Generics,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub id: hir::HirId,
pub whence: Span,
pub name: Name,
@@ -118,14 +118,14 @@ pub struct Enum<'hir> {
pub struct Variant<'hir> {
pub name: Name,
pub id: hir::HirId,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub def: &'hir hir::VariantData,
pub whence: Span,
}

pub struct Function<'hir> {
pub decl: &'hir hir::FnDecl,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub id: hir::HirId,
pub name: Name,
pub vis: &'hir hir::Visibility,
@@ -140,7 +140,7 @@ pub struct Typedef<'hir> {
pub gen: &'hir hir::Generics,
pub name: Name,
pub id: hir::HirId,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub whence: Span,
pub vis: &'hir hir::Visibility,
}
@@ -149,7 +149,7 @@ pub struct OpaqueTy<'hir> {
pub opaque_ty: &'hir hir::OpaqueTy,
pub name: Name,
pub id: hir::HirId,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub whence: Span,
pub vis: &'hir hir::Visibility,
}
@@ -160,7 +160,7 @@ pub struct Static<'hir> {
pub mutability: hir::Mutability,
pub expr: hir::BodyId,
pub name: Name,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub vis: &'hir hir::Visibility,
pub id: hir::HirId,
pub whence: Span,
@@ -170,7 +170,7 @@ pub struct Constant<'hir> {
pub type_: &'hir P<hir::Ty>,
pub expr: hir::BodyId,
pub name: Name,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub vis: &'hir hir::Visibility,
pub id: hir::HirId,
pub whence: Span,
@@ -182,8 +182,8 @@ pub struct Trait<'hir> {
pub name: Name,
pub items: Vec<&'hir hir::TraitItem>,
pub generics: &'hir hir::Generics,
pub bounds: &'hir hir::HirVec<hir::GenericBound>,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub bounds: &'hir [hir::GenericBound],
pub attrs: &'hir [ast::Attribute],
pub id: hir::HirId,
pub whence: Span,
pub vis: &'hir hir::Visibility,
@@ -192,8 +192,8 @@ pub struct Trait<'hir> {
pub struct TraitAlias<'hir> {
pub name: Name,
pub generics: &'hir hir::Generics,
pub bounds: &'hir hir::HirVec<hir::GenericBound>,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub bounds: &'hir [hir::GenericBound],
pub attrs: &'hir [ast::Attribute],
pub id: hir::HirId,
pub whence: Span,
pub vis: &'hir hir::Visibility,
@@ -208,7 +208,7 @@ pub struct Impl<'hir> {
pub trait_: &'hir Option<hir::TraitRef>,
pub for_: &'hir P<hir::Ty>,
pub items: Vec<&'hir hir::ImplItem>,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub whence: Span,
pub vis: &'hir hir::Visibility,
pub id: hir::HirId,
@@ -219,7 +219,7 @@ pub struct ForeignItem<'hir> {
pub id: hir::HirId,
pub name: Name,
pub kind: &'hir hir::ForeignItemKind,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub whence: Span,
}

@@ -229,7 +229,7 @@ pub struct Macro<'hir> {
pub name: Name,
pub hid: hir::HirId,
pub def_id: hir::def_id::DefId,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub whence: Span,
pub matchers: hir::HirVec<Span>,
pub imported_from: Option<Name>,
@@ -240,15 +240,15 @@ pub struct ExternCrate<'hir> {
pub cnum: CrateNum,
pub path: Option<String>,
pub vis: &'hir hir::Visibility,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub whence: Span,
}

pub struct Import<'hir> {
pub name: Name,
pub id: hir::HirId,
pub vis: &'hir hir::Visibility,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub path: &'hir hir::Path,
pub glob: bool,
pub whence: Span,
@@ -259,7 +259,7 @@ pub struct ProcMacro<'hir> {
pub id: hir::HirId,
pub kind: MacroKind,
pub helpers: Vec<Name>,
pub attrs: &'hir hir::HirVec<ast::Attribute>,
pub attrs: &'hir [ast::Attribute],
pub whence: Span,
}

48 changes: 16 additions & 32 deletions src/librustdoc/externalfiles.rs
Original file line number Diff line number Diff line change
@@ -4,9 +4,7 @@ use std::str;
use errors;
use crate::syntax::feature_gate::UnstableFeatures;
use crate::syntax::edition::Edition;
use crate::html::markdown::{IdMap, ErrorCodes, Markdown};

use std::cell::RefCell;
use crate::html::markdown::{IdMap, ErrorCodes, Markdown, Playground};

#[derive(Clone, Debug)]
pub struct ExternalHtml {
@@ -24,37 +22,23 @@ pub struct ExternalHtml {
impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler,
id_map: &mut IdMap, edition: Edition)
id_map: &mut IdMap, edition: Edition, playground: &Option<Playground>)
-> Option<ExternalHtml> {
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
load_external_files(in_header, diag)
.and_then(|ih|
load_external_files(before_content, diag)
.map(|bc| (ih, bc))
)
.and_then(|(ih, bc)|
load_external_files(md_before_content, diag)
.map(|m_bc| (ih,
format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map),
codes, edition))))
)
.and_then(|(ih, bc)|
load_external_files(after_content, diag)
.map(|ac| (ih, bc, ac))
)
.and_then(|(ih, bc, ac)|
load_external_files(md_after_content, diag)
.map(|m_ac| (ih, bc,
format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map),
codes, edition))))
)
.map(|(ih, bc, ac)|
ExternalHtml {
in_header: ih,
before_content: bc,
after_content: ac,
}
)
let ih = load_external_files(in_header, diag)?;
let bc = load_external_files(before_content, diag)?;
let m_bc = load_external_files(md_before_content, diag)?;
let bc = format!("{}{}", bc, Markdown(&m_bc, &[], id_map,
codes, edition, playground).to_string());
let ac = load_external_files(after_content, diag)?;
let m_ac = load_external_files(md_after_content, diag)?;
let ac = format!("{}{}", ac, Markdown(&m_ac, &[], id_map,
codes, edition, playground).to_string());
Some(ExternalHtml {
in_header: ih,
before_content: bc,
after_content: ac,
})
}
}

8 changes: 4 additions & 4 deletions src/librustdoc/fold.rs
Original file line number Diff line number Diff line change
@@ -105,12 +105,12 @@ pub trait DocFolder : Sized {
c.module = c.module.take().and_then(|module| self.fold_item(module));

{
let guard = c.external_traits.lock();
let traits = guard.replace(Default::default());
guard.borrow_mut().extend(traits.into_iter().map(|(k, mut v)| {
let mut guard = c.external_traits.borrow_mut();
let external_traits = std::mem::replace(&mut *guard, Default::default());
*guard = external_traits.into_iter().map(|(k, mut v)| {
v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
(k, v)
}));
}).collect();
}
c
}
259 changes: 133 additions & 126 deletions src/librustdoc/html/markdown.rs

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/librustdoc/html/markdown/tests.rs
Original file line number Diff line number Diff line change
@@ -73,8 +73,8 @@ fn test_lang_string_parse() {
fn test_header() {
fn t(input: &str, expect: &str) {
let mut map = IdMap::new();
let output = Markdown(input, &[], RefCell::new(&mut map),
ErrorCodes::Yes, DEFAULT_EDITION).to_string();
let output = Markdown(
input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
assert_eq!(output, expect, "original: {}", input);
}

@@ -96,8 +96,8 @@ fn test_header() {
fn test_header_ids_multiple_blocks() {
let mut map = IdMap::new();
fn t(map: &mut IdMap, input: &str, expect: &str) {
let output = Markdown(input, &[], RefCell::new(map),
ErrorCodes::Yes, DEFAULT_EDITION).to_string();
let output = Markdown(input, &[], map,
ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
assert_eq!(output, expect, "original: {}", input);
}

@@ -134,8 +134,8 @@ fn test_plain_summary_line() {
fn test_markdown_html_escape() {
fn t(input: &str, expect: &str) {
let mut idmap = IdMap::new();
let output = MarkdownHtml(input, RefCell::new(&mut idmap),
ErrorCodes::Yes, DEFAULT_EDITION).to_string();
let output = MarkdownHtml(input, &mut idmap,
ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
assert_eq!(output, expect, "original: {}", input);
}

52 changes: 28 additions & 24 deletions src/librustdoc/html/render.rs
Original file line number Diff line number Diff line change
@@ -170,6 +170,7 @@ struct Context {
/// The map used to ensure all generated 'id=' attributes are unique.
id_map: Rc<RefCell<IdMap>>,
pub shared: Arc<SharedContext>,
playground: Option<markdown::Playground>,
}

struct SharedContext {
@@ -185,8 +186,8 @@ struct SharedContext {
pub include_sources: bool,
/// The local file sources we've emitted and their respective url-paths.
pub local_sources: FxHashMap<PathBuf, String>,
/// All the passes that were run on this crate.
pub passes: FxHashSet<String>,
/// Whether the collapsed pass ran
pub collapsed: bool,
/// The base-URL of the issue tracker for when an item has been tagged with
/// an issue number.
pub issue_tracker_base_url: Option<String>,
@@ -229,15 +230,10 @@ impl SharedContext {
}

impl SharedContext {
/// Returns `true` if the `collapse-docs` pass was run on this crate.
pub fn was_collapsed(&self) -> bool {
self.passes.contains("collapse-docs")
}

/// Based on whether the `collapse-docs` pass was run, return either the `doc_value` or the
/// `collapsed_doc_value` of the given item.
pub fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<Cow<'a, str>> {
if self.was_collapsed() {
if self.collapsed {
item.collapsed_doc_value().map(|s| s.into())
} else {
item.doc_value().map(|s| s.into())
@@ -526,7 +522,6 @@ pub fn initial_ids() -> Vec<String> {
/// Generates the documentation for `crate` into the directory `dst`
pub fn run(mut krate: clean::Crate,
options: RenderOptions,
passes: FxHashSet<String>,
renderinfo: RenderInfo,
diag: &errors::Handler,
edition: Edition) -> Result<(), Error> {
@@ -557,8 +552,8 @@ pub fn run(mut krate: clean::Crate,
};
let mut errors = Arc::new(ErrorStorage::new());
let mut scx = SharedContext {
collapsed: krate.collapsed,
src_root,
passes,
include_sources: true,
local_sources: Default::default(),
issue_tracker_base_url: None,
@@ -580,9 +575,11 @@ pub fn run(mut krate: clean::Crate,
};

// If user passed in `--playground-url` arg, we fill in crate name here
let mut playground = None;
if let Some(url) = playground_url {
markdown::PLAYGROUND.with(|slot| {
*slot.borrow_mut() = Some((Some(krate.name.clone()), url));
playground = Some(markdown::Playground {
crate_name: Some(krate.name.clone()),
url,
});
}

@@ -598,9 +595,9 @@ pub fn run(mut krate: clean::Crate,
scx.layout.logo = s.to_string();
}
(sym::html_playground_url, Some(s)) => {
markdown::PLAYGROUND.with(|slot| {
let name = krate.name.clone();
*slot.borrow_mut() = Some((Some(name), s.to_string()));
playground = Some(markdown::Playground {
crate_name: Some(krate.name.clone()),
url: s.to_string(),
});
}
(sym::issue_tracker_base_url, Some(s)) => {
@@ -624,6 +621,7 @@ pub fn run(mut krate: clean::Crate,
edition,
id_map: Rc::new(RefCell::new(id_map)),
shared: Arc::new(scx),
playground,
};

// Crawl the crate to build various caches used for the output
@@ -659,7 +657,7 @@ pub fn run(mut krate: clean::Crate,
crate_version: krate.version.take(),
orphan_impl_items: Vec::new(),
orphan_trait_impls: Vec::new(),
traits: krate.external_traits.lock().replace(Default::default()),
traits: krate.external_traits.replace(Default::default()),
deref_trait_did,
deref_mut_trait_did,
owned_box_did,
@@ -2597,8 +2595,8 @@ fn render_markdown(w: &mut fmt::Formatter<'_>,
write!(w, "<div class='docblock{}'>{}{}</div>",
if is_hidden { " hidden" } else { "" },
prefix,
Markdown(md_text, &links, RefCell::new(&mut ids),
cx.codes, cx.edition))
Markdown(md_text, &links, &mut ids,
cx.codes, cx.edition, &cx.playground).to_string())
}

fn document_short(
@@ -2868,7 +2866,7 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context,
</tr>",
name = *myitem.name.as_ref().unwrap(),
stab_tags = stability_tags(myitem),
docs = MarkdownSummaryLine(doc_value, &myitem.links()),
docs = MarkdownSummaryLine(doc_value, &myitem.links()).to_string(),
class = myitem.type_(),
add = add,
stab = stab.unwrap_or_else(|| String::new()),
@@ -2963,8 +2961,8 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {

if let Some(note) = note {
let mut ids = cx.id_map.borrow_mut();
let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes, cx.edition);
message.push_str(&format!(": {}", html));
let html = MarkdownHtml(&note, &mut ids, error_codes, cx.edition, &cx.playground);
message.push_str(&format!(": {}", html.to_string()));
}
stability.push(format!("<div class='stab deprecated'>{}</div>", message));
}
@@ -3012,7 +3010,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
message = format!(
"<details><summary>{}</summary>{}</details>",
message,
MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition)
MarkdownHtml(
&unstable_reason,
&mut ids,
error_codes,
cx.edition,
&cx.playground,
).to_string()
);
}

@@ -4242,8 +4246,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt
if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
let mut ids = cx.id_map.borrow_mut();
write!(w, "<div class='docblock'>{}</div>",
Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids),
cx.codes, cx.edition))?;
Markdown(&*dox, &i.impl_item.links(), &mut ids,
cx.codes, cx.edition, &cx.playground).to_string())?;
}
}

16 changes: 5 additions & 11 deletions src/librustdoc/lib.rs
Original file line number Diff line number Diff line change
@@ -44,7 +44,6 @@ use std::default::Default;
use std::env;
use std::panic;
use std::process;
use std::sync::mpsc::channel;

use rustc::session::{early_warn, early_error};
use rustc::session::config::{ErrorOutputType, RustcOptGroup};
@@ -80,7 +79,6 @@ struct Output {
krate: clean::Crate,
renderinfo: html::render::RenderInfo,
renderopts: config::RenderOptions,
passes: Vec<String>,
}

pub fn main() {
@@ -419,14 +417,13 @@ fn main_options(options: config::Options) -> i32 {
return rustc_driver::EXIT_SUCCESS;
}

let Output { krate, passes, renderinfo, renderopts } = out;
let Output { krate, renderinfo, renderopts } = out;
info!("going to format");
let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts;
let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
match html::render::run(
krate,
renderopts,
passes.into_iter().collect(),
renderinfo,
&diag,
edition,
@@ -454,12 +451,10 @@ where R: 'static + Send,
// First, parse the crate and extract all relevant information.
info!("starting to run rustc");

let (tx, rx) = channel();

let result = rustc_driver::report_ices_to_stderr_if_any(move || {
let crate_name = options.crate_name.clone();
let crate_version = options.crate_version.clone();
let (mut krate, renderinfo, renderopts, passes) = core::run_core(options);
let (mut krate, renderinfo, renderopts) = core::run_core(options);

info!("finished with rustc");

@@ -469,16 +464,15 @@ where R: 'static + Send,

krate.version = crate_version;

tx.send(f(Output {
f(Output {
krate: krate,
renderinfo: renderinfo,
renderopts,
passes: passes
})).unwrap();
})
});

match result {
Ok(()) => rx.recv().unwrap(),
Ok(output) => output,
Err(_) => panic::resume_unwind(Box::new(errors::FatalErrorMarker)),
}
}
12 changes: 6 additions & 6 deletions src/librustdoc/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
use std::cell::RefCell;

use errors;
use testing;
@@ -60,9 +59,10 @@ pub fn render(
};
let playground_url = options.markdown_playground_url
.or(options.playground_url);
if let Some(playground) = playground_url {
markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
}
let playground = playground_url.map(|url| markdown::Playground {
crate_name: None,
url,
});

let mut out = match File::create(&output) {
Err(e) => {
@@ -82,9 +82,9 @@ pub fn render(
let mut ids = IdMap::new();
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let text = if !options.markdown_no_toc {
MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string()
MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).to_string()
} else {
Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string()
Markdown(text, &[], &mut ids, error_codes, edition, &playground).to_string()
};

let err = write!(
4 changes: 3 additions & 1 deletion src/librustdoc/passes/collapse_docs.rs
Original file line number Diff line number Diff line change
@@ -30,7 +30,9 @@ impl DocFragment {
}

pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
Collapser.fold_crate(krate)
let mut krate = Collapser.fold_crate(krate);
krate.collapsed = true;
krate
}

struct Collapser;
4 changes: 2 additions & 2 deletions src/librustdoc/passes/collect_trait_impls.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ use crate::fold::DocFolder;
use super::Pass;

use rustc::util::nodemap::FxHashSet;
use rustc::hir::def_id::DefId;
use rustc::hir::def_id::{LOCAL_CRATE, DefId};
use syntax::symbol::sym;

pub const COLLECT_TRAIT_IMPLS: Pass = Pass {
@@ -116,7 +116,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {

// `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
// doesn't work with it anyway, so pull them from the HIR map instead
for &trait_did in cx.all_traits.iter() {
for &trait_did in cx.tcx.all_traits(LOCAL_CRATE).iter() {
for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
let impl_did = cx.tcx.hir().local_def_id(impl_node);
inline::build_impl(cx, impl_did, None, &mut new_items);
59 changes: 30 additions & 29 deletions src/librustdoc/passes/mod.rs
Original file line number Diff line number Diff line change
@@ -57,8 +57,9 @@ pub struct Pass {
pub description: &'static str,
}


/// The full list of passes.
pub const PASSES: &'static [Pass] = &[
pub const PASSES: &[Pass] = &[
CHECK_PRIVATE_ITEMS_DOC_TESTS,
STRIP_HIDDEN,
UNINDENT_COMMENTS,
@@ -73,43 +74,43 @@ pub const PASSES: &'static [Pass] = &[
];

/// The list of passes run by default.
pub const DEFAULT_PASSES: &[&str] = &[
"collect-trait-impls",
"collapse-docs",
"unindent-comments",
"check-private-items-doc-tests",
"strip-hidden",
"strip-private",
"collect-intra-doc-links",
"check-code-block-syntax",
"propagate-doc-cfg",
pub const DEFAULT_PASSES: &[Pass] = &[
COLLECT_TRAIT_IMPLS,
COLLAPSE_DOCS,
UNINDENT_COMMENTS,
CHECK_PRIVATE_ITEMS_DOC_TESTS,
STRIP_HIDDEN,
STRIP_PRIVATE,
COLLECT_INTRA_DOC_LINKS,
CHECK_CODE_BLOCK_SYNTAX,
PROPAGATE_DOC_CFG,
];

/// The list of default passes run with `--document-private-items` is passed to rustdoc.
pub const DEFAULT_PRIVATE_PASSES: &[&str] = &[
"collect-trait-impls",
"collapse-docs",
"unindent-comments",
"check-private-items-doc-tests",
"strip-priv-imports",
"collect-intra-doc-links",
"check-code-block-syntax",
"propagate-doc-cfg",
pub const DEFAULT_PRIVATE_PASSES: &[Pass] = &[
COLLECT_TRAIT_IMPLS,
COLLAPSE_DOCS,
UNINDENT_COMMENTS,
CHECK_PRIVATE_ITEMS_DOC_TESTS,
STRIP_PRIV_IMPORTS,
COLLECT_INTRA_DOC_LINKS,
CHECK_CODE_BLOCK_SYNTAX,
PROPAGATE_DOC_CFG,
];

/// The list of default passes run when `--doc-coverage` is passed to rustdoc.
pub const DEFAULT_COVERAGE_PASSES: &'static [&'static str] = &[
"collect-trait-impls",
"strip-hidden",
"strip-private",
"calculate-doc-coverage",
pub const DEFAULT_COVERAGE_PASSES: &[Pass] = &[
COLLECT_TRAIT_IMPLS,
STRIP_HIDDEN,
STRIP_PRIVATE,
CALCULATE_DOC_COVERAGE,
];

/// The list of default passes run when `--doc-coverage --document-private-items` is passed to
/// rustdoc.
pub const PRIVATE_COVERAGE_PASSES: &'static [&'static str] = &[
"collect-trait-impls",
"calculate-doc-coverage",
pub const PRIVATE_COVERAGE_PASSES: &[Pass] = &[
COLLECT_TRAIT_IMPLS,
CALCULATE_DOC_COVERAGE,
];

/// A shorthand way to refer to which set of passes to use, based on the presence of
@@ -124,7 +125,7 @@ pub enum DefaultPassOption {
}

/// Returns the given default set of passes.
pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] {
pub fn defaults(default_set: DefaultPassOption) -> &'static [Pass] {
match default_set {
DefaultPassOption::Default => DEFAULT_PASSES,
DefaultPassOption::Private => DEFAULT_PRIVATE_PASSES,
28 changes: 21 additions & 7 deletions src/librustdoc/visit_ast.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ use rustc::hir::def::{Res, DefKind};
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::privacy::AccessLevel;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::ty::TyCtxt;
use syntax::ast;
use syntax::ext::base::MacroKind;
use syntax::source_map::Spanned;
@@ -15,9 +16,26 @@ use syntax_pos::{self, Span};
use std::mem;

use crate::core;
use crate::clean::{self, AttributesExt, NestedAttributesExt, def_id_to_path};
use crate::clean::{self, AttributesExt, NestedAttributesExt};
use crate::doctree::*;

// FIXME: Should this be replaced with tcx.def_path_str?
fn def_id_to_path(
tcx: TyCtxt<'_>,
did: DefId,
) -> Vec<String> {
let crate_name = tcx.crate_name(did.krate).to_string();
let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| {
// extern blocks have an empty name
let s = elem.data.to_string();
if !s.is_empty() {
Some(s)
} else {
None
}
});
std::iter::once(crate_name).chain(relative).collect()
}

// Also, is there some reason that this doesn't use the 'visit'
// framework from syntax?.
@@ -48,12 +66,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
}

fn store_path(&mut self, did: DefId) {
// We can't use the entry API, as that keeps the mutable borrow of `self` active
// when we try to use `cx`.
if self.exact_paths.get(&did).is_none() {
let path = def_id_to_path(self.cx, did, self.cx.crate_name.clone());
self.exact_paths.insert(did, path);
}
let tcx = self.cx.tcx;
self.exact_paths.entry(did).or_insert_with(|| def_id_to_path(tcx, did));
}

pub fn visit(mut self, krate: &'tcx hir::Crate) -> Module<'tcx> {
6 changes: 6 additions & 0 deletions src/libstd/ffi/c_str.rs
Original file line number Diff line number Diff line change
@@ -195,6 +195,12 @@ pub struct CString {
/// [`from_ptr`]: #method.from_ptr
#[derive(Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
// on `CStr` being layout-compatible with `[u8]`.
// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`.
// Anyway, `CStr` representation and layout are considered implementation detail, are
// not documented and must not be relied upon.
pub struct CStr {
// FIXME: this should not be represented with a DST slice but rather with
// just a raw `c_char` along with some form of marker to make
6 changes: 6 additions & 0 deletions src/libstd/ffi/os_str.rs
Original file line number Diff line number Diff line change
@@ -97,6 +97,12 @@ pub struct OsString {
/// [`String`]: ../string/struct.String.html
/// [conversions]: index.html#conversions
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
// `OsStr::from_inner` current implementation relies
// on `OsStr` being layout-compatible with `Slice`.
// When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`.
// Anyway, `OsStr` representation and layout are considered implementation detail, are
// not documented and must not be relied upon.
pub struct OsStr {
inner: Slice
}
12 changes: 12 additions & 0 deletions src/libstd/path.rs
Original file line number Diff line number Diff line change
@@ -1123,6 +1123,12 @@ impl FusedIterator for Ancestors<'_> {}
/// Which method works best depends on what kind of situation you're in.
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
// `PathBuf::as_mut_vec` current implementation relies
// on `PathBuf` being layout-compatible with `Vec<u8>`.
// When attribute privacy is implemented, `PathBuf` should be annotated as `#[repr(transparent)]`.
// Anyway, `PathBuf` representation and layout are considered implementation detail, are
// not documented and must not be relied upon.
pub struct PathBuf {
inner: OsString,
}
@@ -1745,6 +1751,12 @@ impl AsRef<OsStr> for PathBuf {
/// assert_eq!(extension, Some(OsStr::new("txt")));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
// FIXME:
// `Path::new` current implementation relies
// on `Path` being layout-compatible with `OsStr`.
// When attribute privacy is implemented, `Path` should be annotated as `#[repr(transparent)]`.
// Anyway, `Path` representation and layout are considered implementation detail, are
// not documented and must not be relied upon.
pub struct Path {
inner: OsStr,
}
6 changes: 6 additions & 0 deletions src/libstd/sys_common/os_str_bytes.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,12 @@ pub(crate) struct Buf {
pub inner: Vec<u8>
}

// FIXME:
// `Buf::as_slice` current implementation relies
// on `Slice` being layout-compatible with `[u8]`.
// When attribute privacy is implemented, `Slice` should be annotated as `#[repr(transparent)]`.
// Anyway, `Slice` representation and layout are considered implementation detail, are
// not documented and must not be relied upon.
pub(crate) struct Slice {
pub inner: [u8]
}
3 changes: 3 additions & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
@@ -412,6 +412,7 @@ symbols! {
match_beginning_vert,
match_default_bindings,
may_dangle,
mem,
member_constraints,
message,
meta,
@@ -695,6 +696,7 @@ symbols! {
underscore_imports,
underscore_lifetimes,
uniform_paths,
uninitialized,
universal_impl_trait,
unmarked_api,
unreachable_code,
@@ -726,6 +728,7 @@ symbols! {
windows,
windows_subsystem,
Yield,
zeroed,
}
}

4 changes: 2 additions & 2 deletions src/test/ui/consts/uninhabited-const-issue-61744.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// compile-fail

pub const unsafe fn fake_type<T>() -> T {
hint_unreachable()
hint_unreachable() //~ ERROR any use of this value will cause an error
}

pub const unsafe fn hint_unreachable() -> ! {
fake_type() //~ ERROR any use of this value will cause an error
fake_type()
}

trait Const {
57 changes: 53 additions & 4 deletions src/test/ui/consts/uninhabited-const-issue-61744.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,60 @@
error: any use of this value will cause an error
--> $DIR/uninhabited-const-issue-61744.rs:8:5
--> $DIR/uninhabited-const-issue-61744.rs:4:5
|
LL | fake_type()
| ^^^^^^^^^^^
LL | hint_unreachable()
| ^^^^^^^^^^^^^^^^^^
| |
| tried to call a function with return type T passing return place of type !
| reached the configured maximum number of stack frames
| inside call to `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:4:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside call to `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:12:36
...
LL | const CONSTANT: i32 = unsafe { fake_type() };
58 changes: 58 additions & 0 deletions src/test/ui/lint/uninitialized-zeroed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// ignore-tidy-linelength
// This test checks that calling `mem::{uninitialized,zeroed}` with certain types results
// in a lint.

#![feature(never_type)]
#![allow(deprecated)]
#![deny(invalid_value)]

use std::mem::{self, MaybeUninit};

enum Void {}

struct Ref(&'static i32);

struct Wrap<T> { wrapped: T }

#[allow(unused)]
fn generic<T: 'static>() {
unsafe {
let _val: &'static T = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: &'static T = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

let _val: Wrap<&'static T> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: Wrap<&'static T> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
}
}

fn main() {
unsafe {
let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

let _val: (i32, !) = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: (i32, !) = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

let _val: Void = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: Void = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

let _val: &'static i32 = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: &'static i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

let _val: Ref = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: Ref = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

let _val: fn() = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

let _val: Wrap<fn()> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
let _val: Wrap<fn()> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized

// Some types that should work just fine.
let _val: Option<&'static i32> = mem::zeroed();
let _val: Option<fn()> = mem::zeroed();
let _val: MaybeUninit<&'static i32> = mem::zeroed();
let _val: bool = mem::zeroed();
let _val: i32 = mem::zeroed();
}
}
169 changes: 169 additions & 0 deletions src/test/ui/lint/uninitialized-zeroed.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
error: the type `&'static T` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:20:32
|
LL | let _val: &'static T = mem::zeroed();
| ^^^^^^^^^^^^^
|
note: lint level defined here
--> $DIR/uninitialized-zeroed.rs:7:9
|
LL | #![deny(invalid_value)]
| ^^^^^^^^^^^^^
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `&'static T` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:21:32
|
LL | let _val: &'static T = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Wrap<&'static T>` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:23:38
|
LL | let _val: Wrap<&'static T> = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Wrap<&'static T>` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:24:38
|
LL | let _val: Wrap<&'static T> = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `!` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:30:23
|
LL | let _val: ! = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `!` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:31:23
|
LL | let _val: ! = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `(i32, !)` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:33:30
|
LL | let _val: (i32, !) = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `(i32, !)` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:34:30
|
LL | let _val: (i32, !) = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Void` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:36:26
|
LL | let _val: Void = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Void` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:37:26
|
LL | let _val: Void = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `&'static i32` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:39:34
|
LL | let _val: &'static i32 = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `&'static i32` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:40:34
|
LL | let _val: &'static i32 = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Ref` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:42:25
|
LL | let _val: Ref = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Ref` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:43:25
|
LL | let _val: Ref = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `fn()` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:45:26
|
LL | let _val: fn() = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `fn()` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:46:26
|
LL | let _val: fn() = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Wrap<fn()>` does not permit zero-initialization
--> $DIR/uninitialized-zeroed.rs:48:32
|
LL | let _val: Wrap<fn()> = mem::zeroed();
| ^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: the type `Wrap<fn()>` does not permit being left uninitialized
--> $DIR/uninitialized-zeroed.rs:49:32
|
LL | let _val: Wrap<fn()> = mem::uninitialized();
| ^^^^^^^^^^^^^^^^^^^^
|
= note: this means that this code causes undefined behavior when executed
= help: use `MaybeUninit` instead

error: aborting due to 18 previous errors

2 changes: 1 addition & 1 deletion src/test/ui/panic-uninitialized-zeroed.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
// in a runtime panic.

#![feature(never_type)]
#![allow(deprecated)]
#![allow(deprecated, invalid_value)]

use std::{mem, panic};

2 changes: 1 addition & 1 deletion src/tools/clippy
13 changes: 7 additions & 6 deletions src/tools/error_index_generator/main.rs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ use std::cell::RefCell;
use syntax::edition::DEFAULT_EDITION;
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};

use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, PLAYGROUND};
use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, Playground};
use rustc_serialize::json;

enum OutputFormat {
@@ -95,9 +95,13 @@ impl Formatter for HTMLFormatter {
match info.description {
Some(ref desc) => {
let mut id_map = self.0.borrow_mut();
let playground = Playground {
crate_name: None,
url: String::from("https://play.rust-lang.org/"),
};
write!(output, "{}",
Markdown(desc, &[], RefCell::new(&mut id_map),
ErrorCodes::Yes, DEFAULT_EDITION))?
Markdown(desc, &[], &mut id_map,
ErrorCodes::Yes, DEFAULT_EDITION, &Some(playground)).to_string())?
},
None => write!(output, "<p>No description.</p>\n")?,
}
@@ -260,9 +264,6 @@ fn parse_args() -> (OutputFormat, PathBuf) {

fn main() {
env_logger::init();
PLAYGROUND.with(|slot| {
*slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/")));
});
let (format, dst) = parse_args();
let result = syntax::with_default_globals(move || {
main_with_result(format, &dst)