// flesh out rpath support more fully in the future.
cmd.arg("-Z").arg("osx-rpath-install-name");
Some("-Wl,-rpath,@loader_path/../lib")
- } else if !target.contains("windows") && !target.contains("wasm32") {
+ } else if !target.contains("windows") &&
+ !target.contains("wasm32") &&
+ !target.contains("fuchsia") {
Some("-Wl,-rpath,$ORIGIN/../lib")
} else {
None
o("profiler", "build.profiler", "build the profiler runtime")
o("emscripten", None, "compile the emscripten backend as well as LLVM")
o("full-tools", None, "enable all tools")
+o("lld", "rust.lld", "build lld")
o("lldb", "rust.lldb", "build lldb")
o("missing-tools", "dist.missing-tools", "allow failures when building tools")
} else if target != self.config.build &&
!target.contains("msvc") &&
!target.contains("emscripten") &&
- !target.contains("wasm32") {
+ !target.contains("wasm32") &&
+ !target.contains("fuchsia") {
Some(self.cc(target))
} else {
None
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ xz-utils \
+ g++-powerpc-linux-gnuspe \
+ libssl-dev \
+ pkg-config
+
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV HOSTS=powerpc-unknown-linux-gnuspe
+
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++
+ENV CARGO_TARGET_X86_64_FUCHSIA_AR /usr/local/bin/llvm-ar
+ENV CARGO_TARGET_X86_64_FUCHSIA_RUSTFLAGS \
+-C link-arg=--sysroot=/usr/local/x86_64-fuchsia \
+-C link-arg=-L/usr/local/x86_64-fuchsia/lib \
+-C link-arg=-L/usr/local/lib/x86_64-fuchsia/lib
+ENV CARGO_TARGET_AARCH64_FUCHSIA_AR /usr/local/bin/llvm-ar
+ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \
+-C link-arg=--sysroot=/usr/local/aarch64-fuchsia \
+-C link-arg=-L/usr/local/aarch64-fuchsia/lib \
+-C link-arg=-L/usr/local/lib/aarch64-fuchsia/lib
+
ENV TARGETS=x86_64-fuchsia
ENV TARGETS=$TARGETS,aarch64-fuchsia
ENV TARGETS=$TARGETS,sparcv9-sun-solaris
ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs
ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
impl<T: ?Sized> Rc<T> {
// Allocates an `RcBox<T>` with sufficient space for an unsized value
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
- // Create a fake RcBox to find allocation size and alignment
- let fake_ptr = ptr as *mut RcBox<T>;
-
- let layout = Layout::for_value(&*fake_ptr);
+ // Calculate layout using the given value.
+ // Previously, layout was calculated on the expression
+ // `&*(ptr as *const RcBox<T>)`, but this created a misaligned
+ // reference (see #54908).
+ let (layout, _) = Layout::new::<RcBox<()>>()
+ .extend(Layout::for_value(&*ptr)).unwrap();
let mem = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout));
- // Initialize the real RcBox
+ // Initialize the RcBox
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>;
ptr::write(&mut (*inner).strong, Cell::new(1));
impl<T: ?Sized> Arc<T> {
// Allocates an `ArcInner<T>` with sufficient space for an unsized value
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> {
- // Create a fake ArcInner to find allocation size and alignment
- let fake_ptr = ptr as *mut ArcInner<T>;
-
- let layout = Layout::for_value(&*fake_ptr);
+ // Calculate layout using the given value.
+ // Previously, layout was calculated on the expression
+ // `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
+ // reference (see #54908).
+ let (layout, _) = Layout::new::<ArcInner<()>>()
+ .extend(Layout::for_value(&*ptr)).unwrap();
let mem = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout));
- // Initialize the real ArcInner
+ // Initialize the ArcInner
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner<T>;
ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1));
#[cfg(not(target_feature = "atomics"))]
mod lock {
+ #[inline]
pub fn lock() {} // no atomics, no threads, that's easy!
}
}
/// [`bool`]: ../../../std/primitive.bool.html
#[cfg(target_has_atomic = "8")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[repr(C, align(1))]
pub struct AtomicBool {
v: UnsafeCell<u8>,
}
/// This type has the same in-memory representation as a `*mut T`.
#[cfg(target_has_atomic = "ptr")]
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(target_pointer_width = "16", repr(C, align(2)))]
+#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
+#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
pub struct AtomicPtr<T> {
p: UnsafeCell<*mut T>,
}
$s_int_type:expr, $int_ref:expr,
$extra_feature:expr,
$min_fn:ident, $max_fn:ident,
+ $align:expr,
$int_type:ident $atomic_type:ident $atomic_init:ident) => {
/// An integer type which can be safely shared between threads.
///
///
/// [module-level documentation]: index.html
#[$stable]
+ #[repr(C, align($align))]
pub struct $atomic_type {
v: UnsafeCell<$int_type>,
}
"i8", "../../../std/primitive.i8.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
+ 1,
i8 AtomicI8 ATOMIC_I8_INIT
}
#[cfg(target_has_atomic = "8")]
"u8", "../../../std/primitive.u8.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
+ 1,
u8 AtomicU8 ATOMIC_U8_INIT
}
#[cfg(target_has_atomic = "16")]
"i16", "../../../std/primitive.i16.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
+ 2,
i16 AtomicI16 ATOMIC_I16_INIT
}
#[cfg(target_has_atomic = "16")]
"u16", "../../../std/primitive.u16.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
+ 2,
u16 AtomicU16 ATOMIC_U16_INIT
}
#[cfg(target_has_atomic = "32")]
"i32", "../../../std/primitive.i32.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
+ 4,
i32 AtomicI32 ATOMIC_I32_INIT
}
#[cfg(target_has_atomic = "32")]
"u32", "../../../std/primitive.u32.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
+ 4,
u32 AtomicU32 ATOMIC_U32_INIT
}
#[cfg(target_has_atomic = "64")]
"i64", "../../../std/primitive.i64.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
+ 8,
i64 AtomicI64 ATOMIC_I64_INIT
}
#[cfg(target_has_atomic = "64")]
"u64", "../../../std/primitive.u64.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
+ 8,
u64 AtomicU64 ATOMIC_U64_INIT
}
+#[cfg(all(not(stage0), target_has_atomic = "128"))]
+atomic_int! {
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ "i128", "../../../std/primitive.i128.html",
+ "#![feature(integer_atomics)]\n\n",
+ atomic_min, atomic_max,
+ 16,
+ i128 AtomicI128 ATOMIC_I128_INIT
+}
+#[cfg(all(not(stage0), target_has_atomic = "128"))]
+atomic_int! {
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ unstable(feature = "integer_atomics", issue = "32976"),
+ "u128", "../../../std/primitive.u128.html",
+ "#![feature(integer_atomics)]\n\n",
+ atomic_umin, atomic_umax,
+ 16,
+ u128 AtomicU128 ATOMIC_U128_INIT
+}
+#[cfg(target_pointer_width = "16")]
+macro_rules! ptr_width {
+ () => { 2 }
+}
+#[cfg(target_pointer_width = "32")]
+macro_rules! ptr_width {
+ () => { 4 }
+}
+#[cfg(target_pointer_width = "64")]
+macro_rules! ptr_width {
+ () => { 8 }
+}
#[cfg(target_has_atomic = "ptr")]
atomic_int!{
stable(feature = "rust1", since = "1.0.0"),
"isize", "../../../std/primitive.isize.html",
"",
atomic_min, atomic_max,
+ ptr_width!(),
isize AtomicIsize ATOMIC_ISIZE_INIT
}
#[cfg(target_has_atomic = "ptr")]
"usize", "../../../std/primitive.usize.html",
"",
atomic_umin, atomic_umax,
+ ptr_width!(),
usize AtomicUsize ATOMIC_USIZE_INIT
}
return true;
}
- // (To be) stable attribute for #[lang = "panic_impl"]
- if attr::contains_name(attrs, "panic_implementation") ||
- attr::contains_name(attrs, "panic_handler")
- {
+ // Stable attribute for #[lang = "panic_impl"]
+ if attr::contains_name(attrs, "panic_handler") {
return true;
}
if let Some(value) = attribute.value_str() {
return Some((value, attribute.span));
}
- } else if attribute.check_name("panic_implementation") ||
- attribute.check_name("panic_handler")
- {
+ } else if attribute.check_name("panic_handler") {
return Some((Symbol::intern("panic_impl"), attribute.span))
} else if attribute.check_name("alloc_error_handler") {
return Some((Symbol::intern("oom"), attribute.span))
}
}
- pub fn atomic_load(&self, ptr: &'ll Value, order: AtomicOrdering, align: Align) -> &'ll Value {
+ pub fn atomic_load(&self, ptr: &'ll Value, order: AtomicOrdering, size: Size) -> &'ll Value {
self.count_insn("load.atomic");
unsafe {
let load = llvm::LLVMRustBuildAtomicLoad(self.llbuilder, ptr, noname(), order);
- // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here?
- // However, 64-bit atomic loads on `i686-apple-darwin` appear to
- // require `___atomic_load` with ABI-alignment, so it's staying.
- llvm::LLVMSetAlignment(load, align.pref() as c_uint);
+ // LLVM requires the alignment of atomic loads to be at least the size of the type.
+ llvm::LLVMSetAlignment(load, size.bytes() as c_uint);
load
}
}
}
pub fn atomic_store(&self, val: &'ll Value, ptr: &'ll Value,
- order: AtomicOrdering, align: Align) {
+ order: AtomicOrdering, size: Size) {
debug!("Store {:?} -> {:?}", val, ptr);
self.count_insn("store.atomic");
let ptr = self.check_store(val, ptr);
unsafe {
let store = llvm::LLVMRustBuildAtomicStore(self.llbuilder, val, ptr, order);
- // FIXME(eddyb) Isn't it UB to use `pref` instead of `abi` here?
- // Also see `atomic_load` for more context.
- llvm::LLVMSetAlignment(store, align.pref() as c_uint);
+ // LLVM requires the alignment of atomic stores to be at least the size of the type.
+ llvm::LLVMSetAlignment(store, size.bytes() as c_uint);
}
}
"load" => {
let ty = substs.type_at(0);
if int_type_width_signed(ty, cx).is_some() {
- let align = cx.align_of(ty);
- bx.atomic_load(args[0].immediate(), order, align)
+ let size = cx.size_of(ty);
+ bx.atomic_load(args[0].immediate(), order, size)
} else {
return invalid_monomorphization(ty);
}
"store" => {
let ty = substs.type_at(0);
if int_type_width_signed(ty, cx).is_some() {
- let align = cx.align_of(ty);
- bx.atomic_store(args[1].immediate(), args[0].immediate(), order, align);
+ let size = cx.size_of(ty);
+ bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size);
return;
} else {
return invalid_monomorphization(ty);
is non-empty",
pat_ty));
span_help!(&mut err, scrut.span,
- "Please ensure that all possible cases are being handled; \
- possibly adding wildcards or more match arms.");
+ "ensure that all possible cases are being handled, \
+ possibly by adding wildcards or more match arms");
err.emit();
}
// If the type *is* uninhabited, it's vacuously exhaustive
"unchecked_shr" => BinOp::Shr,
_ => bug!("Already checked for int ops")
};
- let (val, overflowed) = self.binary_op_val(bin_op, l, r)?;
+ let (val, overflowed) = self.binary_op_imm(bin_op, l, r)?;
if overflowed {
let layout = self.layout_of(substs.type_at(0))?;
let r_val = r.to_scalar()?.to_bits(layout.size)?;
right: ImmTy<'tcx, M::PointerTag>,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
- let (val, overflowed) = self.binary_op_val(op, left, right)?;
+ let (val, overflowed) = self.binary_op_imm(op, left, right)?;
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
self.write_immediate(val, dest)
}
right: ImmTy<'tcx, M::PointerTag>,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
- let (val, _overflowed) = self.binary_op_val(op, left, right)?;
+ let (val, _overflowed) = self.binary_op_imm(op, left, right)?;
self.write_scalar(val, dest)
}
}
}
/// Convenience wrapper that's useful when keeping the layout together with the
- /// value.
+ /// immediate value.
#[inline]
- pub fn binary_op_val(
+ pub fn binary_op_imm(
&self,
bin_op: mir::BinOp,
left: ImmTy<'tcx, M::PointerTag>,
//
// * First is weak lang items. These are basically mechanisms for
// libcore to forward-reference symbols defined later in crates like
- // the standard library or `#[panic_implementation]` definitions. The
+ // the standard library or `#[panic_handler]` definitions. The
// definition of these weak lang items needs to be referenceable by
// libcore, so we're no longer a candidate for internalization.
// Removal of these functions can't be done by LLVM but rather must be
})?;
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
let (val, overflow) = self.use_ecx(source_info, |this| {
- this.ecx.binary_op_val(op, l, r)
+ this.ecx.binary_op_imm(op, l, r)
})?;
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
Immediate::ScalarPair(
return Err(Determinacy::Determined);
}
}
+ Def::Err => {
+ return Err(Determinacy::Determined);
+ }
_ => panic!("expected `Def::Macro` or `Def::NonMacroAttr`"),
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use spec::{LldFlavor, LinkerFlavor, Target, TargetOptions, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::fuchsia_base::opts();
target_os: "fuchsia".to_string(),
target_env: String::new(),
target_vendor: String::new(),
- linker_flavor: LinkerFlavor::Gcc,
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
options: TargetOptions {
abi_blacklist: super::arm_base::abi_blacklist(),
.. base
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use spec::{LinkArgs, LinkerFlavor, TargetOptions};
+use spec::{LldFlavor, LinkArgs, LinkerFlavor, TargetOptions};
use std::default::Default;
pub fn opts() -> TargetOptions {
let mut args = LinkArgs::new();
- args.insert(LinkerFlavor::Gcc, vec![
- // We want to be able to strip as much executable code as possible
- // from the linker command line, and this flag indicates to the
- // linker that it can avoid linking in dynamic libraries that don't
- // actually satisfy any symbols up to that point (as with many other
- // resolutions the linker does). This option only applies to all
- // following libraries so we're sure to pass it as one of the first
- // arguments.
- // FIXME: figure out whether these linker args are desirable
- //"-Wl,--as-needed".to_string(),
-
- // Always enable NX protection when it is available
- //"-Wl,-z,noexecstack".to_string(),
+ args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec![
+ "--build-id".to_string(), "--hash-style=gnu".to_string(),
+ "-z".to_string(), "rodynamic".to_string(),
]);
TargetOptions {
+ linker: Some("rust-lld".to_owned()),
+ lld_flavor: LldFlavor::Ld,
dynamic_linking: true,
executables: true,
target_family: Some("unix".to_string()),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use spec::{LinkerFlavor, Target, TargetResult};
+use spec::{LldFlavor, LinkerFlavor, Target, TargetResult};
pub fn target() -> TargetResult {
let mut base = super::fuchsia_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.stack_probes = true;
Ok(Target {
target_os: "fuchsia".to_string(),
target_env: String::new(),
target_vendor: String::new(),
- linker_flavor: LinkerFlavor::Gcc,
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
options: base,
})
}
}
}
- // Check that a function marked as `#[panic_implementation]` has signature `fn(&PanicInfo) -> !`
+ // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() {
if panic_impl_did == fcx.tcx.hir.local_def_id(fn_id) {
if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() {
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::{BTreeMap, BTreeSet};
+use std::fmt;
+use std::path::PathBuf;
+
+use errors;
+use errors::emitter::ColorConfig;
+use getopts;
+use rustc::lint::Level;
+use rustc::session::early_error;
+use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
+use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
+ get_cmd_lint_options};
+use rustc::session::search_paths::SearchPaths;
+use rustc_driver;
+use rustc_target::spec::TargetTriple;
+use syntax::edition::Edition;
+
+use core::new_handler;
+use externalfiles::ExternalHtml;
+use html;
+use html::markdown::IdMap;
+use opts;
+use passes::{self, DefaultPassOption};
+use theme;
+
+/// Configuration options for rustdoc.
+#[derive(Clone)]
+pub struct Options {
+ // Basic options / Options passed directly to rustc
+
+ /// The crate root or Markdown file to load.
+ pub input: PathBuf,
+ /// The name of the crate being documented.
+ pub crate_name: Option<String>,
+ /// How to format errors and warnings.
+ pub error_format: ErrorOutputType,
+ /// Library search paths to hand to the compiler.
+ pub libs: SearchPaths,
+ /// The list of external crates to link against.
+ pub externs: Externs,
+ /// List of `cfg` flags to hand to the compiler. Always includes `rustdoc`.
+ pub cfgs: Vec<String>,
+ /// Codegen options to hand to the compiler.
+ pub codegen_options: CodegenOptions,
+ /// Debugging (`-Z`) options to pass to the compiler.
+ pub debugging_options: DebuggingOptions,
+ /// The target used to compile the crate against.
+ pub target: Option<TargetTriple>,
+ /// Edition used when reading the crate. Defaults to "2015". Also used by default when
+ /// compiling doctests from the crate.
+ pub edition: Edition,
+ /// The path to the sysroot. Used during the compilation process.
+ pub maybe_sysroot: Option<PathBuf>,
+ /// Linker to use when building doctests.
+ pub linker: Option<PathBuf>,
+ /// Lint information passed over the command-line.
+ pub lint_opts: Vec<(String, Level)>,
+ /// Whether to ask rustc to describe the lints it knows. Practically speaking, this will not be
+ /// used, since we abort if we have no input file, but it's included for completeness.
+ pub describe_lints: bool,
+ /// What level to cap lints at.
+ pub lint_cap: Option<Level>,
+
+ // Options specific to running doctests
+
+ /// Whether we should run doctests instead of generating docs.
+ pub should_test: bool,
+ /// List of arguments to pass to the test harness, if running tests.
+ pub test_args: Vec<String>,
+
+ // Options that affect the documentation process
+
+ /// The selected default set of passes to use.
+ ///
+ /// Be aware: This option can come both from the CLI and from crate attributes!
+ pub default_passes: DefaultPassOption,
+ /// Any passes manually selected by the user.
+ ///
+ /// Be aware: This option can come both from the CLI and from crate attributes!
+ pub manual_passes: Vec<String>,
+ /// Whether to display warnings during doc generation or while gathering doctests. By default,
+ /// all non-rustdoc-specific lints are allowed when generating docs.
+ pub display_warnings: bool,
+
+ // Options that alter generated documentation pages
+
+ /// Crate version to note on the sidebar of generated docs.
+ pub crate_version: Option<String>,
+ /// Collected options specific to outputting final pages.
+ pub render_options: RenderOptions,
+}
+
+impl fmt::Debug for Options {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ struct FmtExterns<'a>(&'a Externs);
+
+ impl<'a> fmt::Debug for FmtExterns<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_map()
+ .entries(self.0.iter())
+ .finish()
+ }
+ }
+
+ f.debug_struct("Options")
+ .field("input", &self.input)
+ .field("crate_name", &self.crate_name)
+ .field("error_format", &self.error_format)
+ .field("libs", &self.libs)
+ .field("externs", &FmtExterns(&self.externs))
+ .field("cfgs", &self.cfgs)
+ .field("codegen_options", &"...")
+ .field("debugging_options", &"...")
+ .field("target", &self.target)
+ .field("edition", &self.edition)
+ .field("maybe_sysroot", &self.maybe_sysroot)
+ .field("linker", &self.linker)
+ .field("lint_opts", &self.lint_opts)
+ .field("describe_lints", &self.describe_lints)
+ .field("lint_cap", &self.lint_cap)
+ .field("should_test", &self.should_test)
+ .field("test_args", &self.test_args)
+ .field("default_passes", &self.default_passes)
+ .field("manual_passes", &self.manual_passes)
+ .field("display_warnings", &self.display_warnings)
+ .field("crate_version", &self.crate_version)
+ .field("render_options", &self.render_options)
+ .finish()
+ }
+}
+
+/// Configuration options for the HTML page-creation process.
+#[derive(Clone, Debug)]
+pub struct RenderOptions {
+ /// Output directory to generate docs into. Defaults to `doc`.
+ pub output: PathBuf,
+ /// External files to insert into generated pages.
+ pub external_html: ExternalHtml,
+ /// A pre-populated `IdMap` with the default headings and any headings added by Markdown files
+ /// processed by `external_html`.
+ pub id_map: IdMap,
+ /// If present, playground URL to use in the "Run" button added to code samples.
+ ///
+ /// Be aware: This option can come both from the CLI and from crate attributes!
+ pub playground_url: Option<String>,
+ /// Whether to sort modules alphabetically on a module page instead of using declaration order.
+ /// `true` by default.
+ ///
+ /// FIXME(misdreavus): the flag name is `--sort-modules-by-appearance` but the meaning is
+ /// inverted once read
+ pub sort_modules_alphabetically: bool,
+ /// List of themes to extend the docs with. Original argument name is included to assist in
+ /// displaying errors if it fails a theme check.
+ pub themes: Vec<PathBuf>,
+ /// If present, CSS file that contains rules to add to the default CSS.
+ pub extension_css: Option<PathBuf>,
+ /// A map of crate names to the URL to use instead of querying the crate's `html_root_url`.
+ pub extern_html_root_urls: BTreeMap<String, String>,
+ /// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
+ pub resource_suffix: String,
+ /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
+ /// default.
+ ///
+ /// FIXME(misdreavus): the flag name is `--disable-minification` but the meaning is inverted
+ /// once read
+ pub enable_minification: bool,
+ /// Whether to create an index page in the root of the output directory. If this is true but
+ /// `enable_index_page` is None, generate a static listing of crates instead.
+ pub enable_index_page: bool,
+ /// A file to use as the index page at the root of the output directory. Overrides
+ /// `enable_index_page` to be true if set.
+ pub index_page: Option<PathBuf>,
+
+ // Options specific to reading standalone Markdown files
+
+ /// Whether to generate a table of contents on the output file when reading a standalone
+ /// Markdown file.
+ pub markdown_no_toc: bool,
+ /// Additional CSS files to link in pages generated from standlone Markdown files.
+ pub markdown_css: Vec<String>,
+ /// If present, playground URL to use in the "Run" button added to code samples generated from
+ /// standalone Markdown files. If not present, `playground_url` is used.
+ pub markdown_playground_url: Option<String>,
+}
+
+impl Options {
+ /// Parses the given command-line for options. If an error message or other early-return has
+ /// been printed, returns `Err` with the exit code.
+ pub fn from_matches(matches: &getopts::Matches) -> Result<Options, isize> {
+ // Check for unstable options.
+ nightly_options::check_nightly_options(&matches, &opts());
+
+ if matches.opt_present("h") || matches.opt_present("help") {
+ ::usage("rustdoc");
+ return Err(0);
+ } else if matches.opt_present("version") {
+ rustc_driver::version("rustdoc", &matches);
+ return Err(0);
+ }
+
+ if matches.opt_strs("passes") == ["list"] {
+ println!("Available passes for running rustdoc:");
+ for pass in passes::PASSES {
+ println!("{:>20} - {}", pass.name(), pass.description());
+ }
+ println!("\nDefault passes for rustdoc:");
+ for &name in passes::DEFAULT_PASSES {
+ println!("{:>20}", name);
+ }
+ println!("\nPasses run with `--document-private-items`:");
+ for &name in passes::DEFAULT_PRIVATE_PASSES {
+ println!("{:>20}", name);
+ }
+ return Err(0);
+ }
+
+ let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
+ Some("auto") => ColorConfig::Auto,
+ Some("always") => ColorConfig::Always,
+ Some("never") => ColorConfig::Never,
+ None => ColorConfig::Auto,
+ Some(arg) => {
+ early_error(ErrorOutputType::default(),
+ &format!("argument for --color must be `auto`, `always` or `never` \
+ (instead was `{}`)", arg));
+ }
+ };
+ let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
+ Some("human") => ErrorOutputType::HumanReadable(color),
+ Some("json") => ErrorOutputType::Json(false),
+ Some("pretty-json") => ErrorOutputType::Json(true),
+ Some("short") => ErrorOutputType::Short(color),
+ None => ErrorOutputType::HumanReadable(color),
+ Some(arg) => {
+ early_error(ErrorOutputType::default(),
+ &format!("argument for --error-format must be `human`, `json` or \
+ `short` (instead was `{}`)", arg));
+ }
+ };
+
+ let codegen_options = build_codegen_options(matches, error_format);
+ let debugging_options = build_debugging_options(matches, error_format);
+
+ let diag = new_handler(error_format,
+ None,
+ debugging_options.treat_err_as_bug,
+ debugging_options.ui_testing);
+
+ // check for deprecated options
+ check_deprecated_options(&matches, &diag);
+
+ let to_check = matches.opt_strs("theme-checker");
+ if !to_check.is_empty() {
+ let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
+ let mut errors = 0;
+
+ println!("rustdoc: [theme-checker] Starting tests!");
+ for theme_file in to_check.iter() {
+ print!(" - Checking \"{}\"...", theme_file);
+ let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
+ if !differences.is_empty() || !success {
+ println!(" FAILED");
+ errors += 1;
+ if !differences.is_empty() {
+ println!("{}", differences.join("\n"));
+ }
+ } else {
+ println!(" OK");
+ }
+ }
+ if errors != 0 {
+ return Err(1);
+ }
+ return Err(0);
+ }
+
+ if matches.free.is_empty() {
+ diag.struct_err("missing file operand").emit();
+ return Err(1);
+ }
+ if matches.free.len() > 1 {
+ diag.struct_err("too many file operands").emit();
+ return Err(1);
+ }
+ let input = PathBuf::from(&matches.free[0]);
+
+ let mut libs = SearchPaths::new();
+ for s in &matches.opt_strs("L") {
+ libs.add_path(s, error_format);
+ }
+ let externs = match parse_externs(&matches) {
+ Ok(ex) => ex,
+ Err(err) => {
+ diag.struct_err(&err).emit();
+ return Err(1);
+ }
+ };
+ let extern_html_root_urls = match parse_extern_html_roots(&matches) {
+ Ok(ex) => ex,
+ Err(err) => {
+ diag.struct_err(err).emit();
+ return Err(1);
+ }
+ };
+
+ let test_args = matches.opt_strs("test-args");
+ let test_args: Vec<String> = test_args.iter()
+ .flat_map(|s| s.split_whitespace())
+ .map(|s| s.to_string())
+ .collect();
+
+ let should_test = matches.opt_present("test");
+
+ let output = matches.opt_str("o")
+ .map(|s| PathBuf::from(&s))
+ .unwrap_or_else(|| PathBuf::from("doc"));
+ let mut cfgs = matches.opt_strs("cfg");
+ cfgs.push("rustdoc".to_string());
+
+ let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s));
+
+ if let Some(ref p) = extension_css {
+ if !p.is_file() {
+ diag.struct_err("option --extend-css argument must be a file").emit();
+ return Err(1);
+ }
+ }
+
+ let mut themes = Vec::new();
+ if matches.opt_present("themes") {
+ let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
+
+ for (theme_file, theme_s) in matches.opt_strs("themes")
+ .iter()
+ .map(|s| (PathBuf::from(&s), s.to_owned())) {
+ if !theme_file.is_file() {
+ diag.struct_err("option --themes arguments must all be files").emit();
+ return Err(1);
+ }
+ let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
+ if !success || !ret.is_empty() {
+ diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
+ .help("check what's wrong with the --theme-checker option")
+ .emit();
+ return Err(1);
+ }
+ themes.push(theme_file);
+ }
+ }
+
+ let mut id_map = html::markdown::IdMap::new();
+ id_map.populate(html::render::initial_ids());
+ let external_html = match ExternalHtml::load(
+ &matches.opt_strs("html-in-header"),
+ &matches.opt_strs("html-before-content"),
+ &matches.opt_strs("html-after-content"),
+ &matches.opt_strs("markdown-before-content"),
+ &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
+ Some(eh) => eh,
+ None => return Err(3),
+ };
+
+ let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
+ let edition = match edition.parse() {
+ Ok(e) => e,
+ Err(_) => {
+ diag.struct_err("could not parse edition").emit();
+ return Err(1);
+ }
+ };
+
+ match matches.opt_str("r").as_ref().map(|s| &**s) {
+ Some("rust") | None => {}
+ Some(s) => {
+ diag.struct_err(&format!("unknown input format: {}", s)).emit();
+ return Err(1);
+ }
+ }
+
+ match matches.opt_str("w").as_ref().map(|s| &**s) {
+ Some("html") | None => {}
+ Some(s) => {
+ diag.struct_err(&format!("unknown output format: {}", s)).emit();
+ return Err(1);
+ }
+ }
+
+ let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
+ if let Some(ref index_page) = index_page {
+ if !index_page.is_file() {
+ diag.struct_err("option `--index-page` argument must be a file").emit();
+ return Err(1);
+ }
+ }
+
+ let target = matches.opt_str("target").map(|target| {
+ if target.ends_with(".json") {
+ TargetTriple::TargetPath(PathBuf::from(target))
+ } else {
+ TargetTriple::TargetTriple(target)
+ }
+ });
+
+ let default_passes = if matches.opt_present("no-defaults") {
+ passes::DefaultPassOption::None
+ } else if matches.opt_present("document-private-items") {
+ passes::DefaultPassOption::Private
+ } else {
+ passes::DefaultPassOption::Default
+ };
+ let manual_passes = matches.opt_strs("passes");
+
+ let crate_name = matches.opt_str("crate-name");
+ let playground_url = matches.opt_str("playground-url");
+ let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
+ let display_warnings = matches.opt_present("display-warnings");
+ let linker = matches.opt_str("linker").map(PathBuf::from);
+ let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
+ let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
+ let enable_minification = !matches.opt_present("disable-minification");
+ let markdown_no_toc = matches.opt_present("markdown-no-toc");
+ let markdown_css = matches.opt_strs("markdown-css");
+ let markdown_playground_url = matches.opt_str("markdown-playground-url");
+ let crate_version = matches.opt_str("crate-version");
+ let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
+
+ let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+
+ Ok(Options {
+ input,
+ crate_name,
+ error_format,
+ libs,
+ externs,
+ cfgs,
+ codegen_options,
+ debugging_options,
+ target,
+ edition,
+ maybe_sysroot,
+ linker,
+ lint_opts,
+ describe_lints,
+ lint_cap,
+ should_test,
+ test_args,
+ default_passes,
+ manual_passes,
+ display_warnings,
+ crate_version,
+ render_options: RenderOptions {
+ output,
+ external_html,
+ id_map,
+ playground_url,
+ sort_modules_alphabetically,
+ themes,
+ extension_css,
+ extern_html_root_urls,
+ resource_suffix,
+ enable_minification,
+ enable_index_page,
+ index_page,
+ markdown_no_toc,
+ markdown_css,
+ markdown_playground_url,
+ }
+ })
+ }
+
+ /// Returns whether the file given as `self.input` is a Markdown file.
+ pub fn markdown_input(&self) -> bool {
+ self.input.extension()
+ .map_or(false, |e| e == "md" || e == "markdown")
+ }
+}
+
+/// Prints deprecation warnings for deprecated options
+fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
+ let deprecated_flags = [
+ "input-format",
+ "output-format",
+ "no-defaults",
+ "passes",
+ ];
+
+ for flag in deprecated_flags.into_iter() {
+ if matches.opt_present(flag) {
+ let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
+ flag));
+ err.warn("please see https://github.com/rust-lang/rust/issues/44136");
+
+ if *flag == "no-defaults" {
+ err.help("you may want to use --document-private-items");
+ }
+
+ err.emit();
+ }
+ }
+
+ let removed_flags = [
+ "plugins",
+ "plugin-path",
+ ];
+
+ for &flag in removed_flags.iter() {
+ if matches.opt_present(flag) {
+ diag.struct_warn(&format!("the '{}' flag no longer functions", flag))
+ .warn("see CVE-2018-1000622")
+ .emit();
+ }
+ }
+}
+
+/// Extracts `--extern-html-root-url` arguments from `matches` and returns a map of crate names to
+/// the given URLs. If an `--extern-html-root-url` argument was ill-formed, returns an error
+/// describing the issue.
+fn parse_extern_html_roots(
+ matches: &getopts::Matches,
+) -> Result<BTreeMap<String, String>, &'static str> {
+ let mut externs = BTreeMap::new();
+ for arg in &matches.opt_strs("extern-html-root-url") {
+ let mut parts = arg.splitn(2, '=');
+ let name = parts.next().ok_or("--extern-html-root-url must not be empty")?;
+ let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?;
+ externs.insert(name.to_string(), url.to_string());
+ }
+
+ Ok(externs)
+}
+
+/// Extracts `--extern CRATE=PATH` arguments from `matches` and
+/// returns a map mapping crate names to their paths or else an
+/// error message.
+// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
+fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
+ let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
+ for arg in &matches.opt_strs("extern") {
+ let mut parts = arg.splitn(2, '=');
+ let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
+ let location = parts.next().map(|s| s.to_string());
+ if location.is_none() && !nightly_options::is_unstable_enabled(matches) {
+ return Err("the `-Z unstable-options` flag must also be passed to \
+ enable `--extern crate_name` without `=path`".to_string());
+ }
+ let name = name.to_string();
+ externs.entry(name).or_default().insert(location);
+ }
+ Ok(Externs::new(externs))
+}
use syntax::ast::{self, Ident, NodeId};
use syntax::source_map;
-use syntax::edition::Edition;
use syntax::feature_gate::UnstableFeatures;
use syntax::json::JsonEmitter;
use syntax::ptr::P;
use rustc_data_structures::sync::{self, Lrc};
use std::rc::Rc;
use std::sync::Arc;
-use std::path::PathBuf;
use visit_ast::RustdocVisitor;
+use config::{Options as RustdocOptions, RenderOptions};
use clean;
use clean::{get_path_for_type, Clean, MAX_DEF_ID, AttributesExt};
use html::render::RenderInfo;
)
}
-pub fn run_core(search_paths: SearchPaths,
- cfgs: Vec<String>,
- externs: config::Externs,
- input: Input,
- triple: Option<TargetTriple>,
- maybe_sysroot: Option<PathBuf>,
- allow_warnings: bool,
- crate_name: Option<String>,
- force_unstable_if_unmarked: bool,
- edition: Edition,
- cg: CodegenOptions,
- error_format: ErrorOutputType,
- cmd_lints: Vec<(String, lint::Level)>,
- lint_cap: Option<lint::Level>,
- describe_lints: bool,
- mut manual_passes: Vec<String>,
- mut default_passes: passes::DefaultPassOption,
- treat_err_as_bug: bool,
- ui_testing: bool,
-) -> (clean::Crate, RenderInfo, Vec<String>) {
+pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions, Vec<String>) {
// Parse, resolve, and typecheck the given crate.
- let cpath = match input {
- Input::File(ref p) => Some(p.clone()),
- _ => None
- };
+ let RustdocOptions {
+ input,
+ crate_name,
+ error_format,
+ libs,
+ externs,
+ cfgs,
+ codegen_options,
+ debugging_options,
+ target,
+ edition,
+ maybe_sysroot,
+ lint_opts,
+ describe_lints,
+ lint_cap,
+ mut default_passes,
+ mut manual_passes,
+ display_warnings,
+ render_options,
+ ..
+ } = options;
+
+ let cpath = Some(input.clone());
+ let input = Input::File(input);
let intra_link_resolution_failure_name = lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE.name;
let warnings_lint_name = lint::builtin::WARNINGS.name;
missing_docs.to_owned(),
missing_doc_example.to_owned()];
- whitelisted_lints.extend(cmd_lints.iter().map(|(lint, _)| lint).cloned());
+ whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned());
let lints = lint::builtin::HardwiredLints.get_lints()
.into_iter()
Some((lint.name_lower(), lint::Allow))
}
})
- .chain(cmd_lints.into_iter())
+ .chain(lint_opts.into_iter())
.collect::<Vec<_>>();
let host_triple = TargetTriple::from_triple(config::host_triple());
// plays with error output here!
let sessopts = config::Options {
maybe_sysroot,
- search_paths,
+ search_paths: libs,
crate_types: vec![config::CrateType::Rlib],
- lint_opts: if !allow_warnings {
+ lint_opts: if !display_warnings {
lints
} else {
vec![]
},
lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)),
- cg,
+ cg: codegen_options,
externs,
- target_triple: triple.unwrap_or(host_triple),
+ target_triple: target.unwrap_or(host_triple),
// Ensure that rustdoc works even if rustc is feature-staged
unstable_features: UnstableFeatures::Allow,
actually_rustdoc: true,
- debugging_opts: config::DebuggingOptions {
- force_unstable_if_unmarked,
- treat_err_as_bug,
- ui_testing,
- ..config::basic_debugging_options()
- },
+ debugging_opts: debugging_options.clone(),
error_format,
edition,
describe_lints,
let source_map = Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()));
let diagnostic_handler = new_handler(error_format,
Some(source_map.clone()),
- treat_err_as_bug,
- ui_testing);
+ debugging_options.treat_err_as_bug,
+ debugging_options.ui_testing);
let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, source_map,
ctxt.sess().abort_if_errors();
- (krate, ctxt.renderinfo.into_inner(), passes)
+ (krate, ctxt.renderinfo.into_inner(), render_options, passes)
}), &sess)
})
}
use html::markdown::{IdMap, ErrorCodes, Markdown};
use std::cell::RefCell;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct ExternalHtml {
/// Content that will be included inline in the <head> section of a
/// rendered Markdown file or generated documentation
links
}
-#[derive(Default)]
+#[derive(Clone, Default, Debug)]
pub struct IdMap {
map: FxHashMap<String, usize>,
}
use std::sync::Arc;
use std::rc::Rc;
-use externalfiles::ExternalHtml;
-
use errors;
-use getopts;
-
use serialize::json::{ToJson, Json, as_json};
use syntax::ast;
use syntax::ext::base::MacroKind;
use rustc_data_structures::flock;
use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability};
+use config::RenderOptions;
use doctree;
use fold::DocFolder;
use html::escape::Escape;
/// The map used to ensure all generated 'id=' attributes are unique.
id_map: Rc<RefCell<IdMap>>,
pub shared: Arc<SharedContext>,
- pub enable_index_page: bool,
- pub index_page: Option<PathBuf>,
}
struct SharedContext {
/// Generates the documentation for `crate` into the directory `dst`
pub fn run(mut krate: clean::Crate,
- extern_urls: BTreeMap<String, String>,
- external_html: &ExternalHtml,
- playground_url: Option<String>,
- dst: PathBuf,
- resource_suffix: String,
+ options: RenderOptions,
passes: FxHashSet<String>,
- css_file_extension: Option<PathBuf>,
renderinfo: RenderInfo,
- sort_modules_alphabetically: bool,
- themes: Vec<PathBuf>,
- enable_minification: bool,
- id_map: IdMap,
- enable_index_page: bool,
- index_page: Option<PathBuf>,
- matches: &getopts::Matches,
- diag: &errors::Handler,
-) -> Result<(), Error> {
+ diag: &errors::Handler) -> Result<(), Error> {
+ // need to save a copy of the options for rendering the index page
+ let md_opts = options.clone();
+ let RenderOptions {
+ output,
+ external_html,
+ id_map,
+ playground_url,
+ sort_modules_alphabetically,
+ themes,
+ extension_css,
+ extern_html_root_urls,
+ resource_suffix,
+ ..
+ } = options;
+
let src_root = match krate.src {
FileName::Real(ref p) => match p.parent() {
Some(p) => p.to_path_buf(),
layout: layout::Layout {
logo: String::new(),
favicon: String::new(),
- external_html: external_html.clone(),
+ external_html,
krate: krate.name.clone(),
},
- css_file_extension,
+ css_file_extension: extension_css,
created_dirs: Default::default(),
sort_modules_alphabetically,
themes,
}
}
}
+ let dst = output;
try_err!(fs::create_dir_all(&dst), &dst);
krate = render_sources(&dst, &mut scx, krate)?;
let cx = Context {
codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()),
id_map: Rc::new(RefCell::new(id_map)),
shared: Arc::new(scx),
- enable_index_page,
- index_page,
};
// Crawl the crate to build various caches used for the output
},
_ => PathBuf::new(),
};
- let extern_url = extern_urls.get(&e.name).map(|u| &**u);
+ let extern_url = extern_html_root_urls.get(&e.name).map(|u| &**u);
cache.extern_locations.insert(n, (e.name.clone(), src_root,
extern_location(e, extern_url, &cx.dst)));
CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
- write_shared(&cx, &krate, &*cache, index, enable_minification, matches, diag)?;
+ write_shared(&cx, &krate, &*cache, index, &md_opts, diag)?;
// And finally render the whole crate's documentation
cx.krate(krate)
krate: &clean::Crate,
cache: &Cache,
search_index: String,
- enable_minification: bool,
- matches: &getopts::Matches,
+ options: &RenderOptions,
diag: &errors::Handler,
) -> Result<(), Error> {
// Write out the shared files. Note that these are shared among all rustdoc
write_minify(cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)),
include_str!("static/rustdoc.css"),
- enable_minification)?;
+ options.enable_minification)?;
write_minify(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
include_str!("static/settings.css"),
- enable_minification)?;
+ options.enable_minification)?;
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
// then we'll run over the "official" styles.
include_bytes!("static/wheel.svg"))?;
write_minify(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
include_str!("static/themes/light.css"),
- enable_minification)?;
+ options.enable_minification)?;
themes.insert("light".to_owned());
write_minify(cx.dst.join(&format!("dark{}.css", cx.shared.resource_suffix)),
include_str!("static/themes/dark.css"),
- enable_minification)?;
+ options.enable_minification)?;
themes.insert("dark".to_owned());
let mut themes: Vec<&String> = themes.iter().collect();
write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
include_str!("static/main.js"),
- enable_minification)?;
+ options.enable_minification)?;
write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
include_str!("static/settings.js"),
- enable_minification)?;
+ options.enable_minification)?;
{
let mut data = format!("var resourcesSuffix = \"{}\";\n",
data.push_str(include_str!("static/storage.js"));
write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
&data,
- enable_minification)?;
+ options.enable_minification)?;
}
if let Some(ref css) = cx.shared.css_file_extension {
let out = cx.dst.join(&format!("theme{}.css", cx.shared.resource_suffix));
- if !enable_minification {
+ if !options.enable_minification {
try_err!(fs::copy(css, out), css);
} else {
let mut f = try_err!(File::open(css), css);
let mut buffer = String::with_capacity(1000);
try_err!(f.read_to_string(&mut buffer), css);
- write_minify(out, &buffer, enable_minification)?;
+ write_minify(out, &buffer, options.enable_minification)?;
}
}
write_minify(cx.dst.join(&format!("normalize{}.css", cx.shared.resource_suffix)),
include_str!("static/normalize.css"),
- enable_minification)?;
+ options.enable_minification)?;
write(cx.dst.join("FiraSans-Regular.woff"),
include_bytes!("static/FiraSans-Regular.woff"))?;
write(cx.dst.join("FiraSans-Medium.woff"),
let mut w = try_err!(File::create(&dst), &dst);
try_err!(writeln!(&mut w, "var N = null;var searchIndex = {{}};"), &dst);
for index in &all_indexes {
- try_err!(write_minify_replacer(&mut w, &*index, enable_minification,
+ try_err!(write_minify_replacer(&mut w, &*index, options.enable_minification,
&[(minifier::js::Keyword::Null, "N")]),
&dst);
}
try_err!(writeln!(&mut w, "initSearch(searchIndex);"), &dst);
- if cx.enable_index_page == true {
- if let Some(ref index_page) = cx.index_page {
- ::markdown::render(index_page,
- cx.dst.clone(),
- &matches, &(*cx.shared).layout.external_html,
- !matches.opt_present("markdown-no-toc"),
- diag);
+ if options.enable_index_page {
+ if let Some(index_page) = options.index_page.clone() {
+ let mut md_opts = options.clone();
+ md_opts.output = cx.dst.clone();
+ md_opts.external_html = (*cx.shared).layout.external_html.clone();
+
+ ::markdown::render(index_page, md_opts, diag);
} else {
let dst = cx.dst.join("index.html");
let mut w = BufWriter::new(try_err!(File::create(&dst), &dst));
extern crate serialize as rustc_serialize; // used by deriving
-use errors::ColorConfig;
-
-use std::collections::{BTreeMap, BTreeSet};
use std::default::Default;
use std::env;
use std::panic;
-use std::path::{Path, PathBuf};
use std::process;
use std::sync::mpsc::channel;
-use syntax::edition::Edition;
-use externalfiles::ExternalHtml;
use rustc::session::{early_warn, early_error};
-use rustc::session::search_paths::SearchPaths;
-use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions};
-use rustc::session::config::{nightly_options, build_codegen_options};
-use rustc_target::spec::TargetTriple;
-use rustc::session::config::get_cmd_lint_options;
+use rustc::session::config::{ErrorOutputType, RustcOptGroup};
#[macro_use]
mod externalfiles;
mod clean;
+mod config;
mod core;
mod doctree;
mod fold;
struct Output {
krate: clean::Crate,
renderinfo: html::render::RenderInfo,
+ renderopts: config::RenderOptions,
passes: Vec<String>,
}
early_error(ErrorOutputType::default(), &err.to_string());
}
};
- // Check for unstable options.
- nightly_options::check_nightly_options(&matches, &opts());
-
- if matches.opt_present("h") || matches.opt_present("help") {
- usage("rustdoc");
- return 0;
- } else if matches.opt_present("version") {
- rustc_driver::version("rustdoc", &matches);
- return 0;
- }
-
- if matches.opt_strs("passes") == ["list"] {
- println!("Available passes for running rustdoc:");
- for pass in passes::PASSES {
- println!("{:>20} - {}", pass.name(), pass.description());
- }
- println!("\nDefault passes for rustdoc:");
- for &name in passes::DEFAULT_PASSES {
- println!("{:>20}", name);
- }
- println!("\nPasses run with `--document-private-items`:");
- for &name in passes::DEFAULT_PRIVATE_PASSES {
- println!("{:>20}", name);
- }
- return 0;
- }
-
- let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
- Some("auto") => ColorConfig::Auto,
- Some("always") => ColorConfig::Always,
- Some("never") => ColorConfig::Never,
- None => ColorConfig::Auto,
- Some(arg) => {
- early_error(ErrorOutputType::default(),
- &format!("argument for --color must be `auto`, `always` or `never` \
- (instead was `{}`)", arg));
- }
+ let options = match config::Options::from_matches(&matches) {
+ Ok(opts) => opts,
+ Err(code) => return code,
};
- let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
- Some("human") => ErrorOutputType::HumanReadable(color),
- Some("json") => ErrorOutputType::Json(false),
- Some("pretty-json") => ErrorOutputType::Json(true),
- Some("short") => ErrorOutputType::Short(color),
- None => ErrorOutputType::HumanReadable(color),
- Some(arg) => {
- early_error(ErrorOutputType::default(),
- &format!("argument for --error-format must be `human`, `json` or \
- `short` (instead was `{}`)", arg));
- }
- };
- let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
- *x == "treat-err-as-bug"
- });
- let ui_testing = matches.opt_strs("Z").iter().any(|x| {
- *x == "ui-testing"
- });
-
- let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
-
- // check for deprecated options
- check_deprecated_options(&matches, &diag);
-
- let to_check = matches.opt_strs("theme-checker");
- if !to_check.is_empty() {
- let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
- let mut errors = 0;
-
- println!("rustdoc: [theme-checker] Starting tests!");
- for theme_file in to_check.iter() {
- print!(" - Checking \"{}\"...", theme_file);
- let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
- if !differences.is_empty() || !success {
- println!(" FAILED");
- errors += 1;
- if !differences.is_empty() {
- println!("{}", differences.join("\n"));
- }
- } else {
- println!(" OK");
- }
- }
- if errors != 0 {
- return 1;
- }
- return 0;
- }
-
- if matches.free.is_empty() {
- diag.struct_err("missing file operand").emit();
- return 1;
- }
- if matches.free.len() > 1 {
- diag.struct_err("too many file operands").emit();
- return 1;
- }
- let input = matches.free[0].clone();
-
- let mut libs = SearchPaths::new();
- for s in &matches.opt_strs("L") {
- libs.add_path(s, error_format);
- }
- let externs = match parse_externs(&matches) {
- Ok(ex) => ex,
- Err(err) => {
- diag.struct_err(&err).emit();
- return 1;
- }
- };
- let extern_urls = match parse_extern_html_roots(&matches) {
- Ok(ex) => ex,
- Err(err) => {
- diag.struct_err(err).emit();
- return 1;
- }
- };
-
- let test_args = matches.opt_strs("test-args");
- let test_args: Vec<String> = test_args.iter()
- .flat_map(|s| s.split_whitespace())
- .map(|s| s.to_string())
- .collect();
-
- let should_test = matches.opt_present("test");
- let markdown_input = Path::new(&input).extension()
- .map_or(false, |e| e == "md" || e == "markdown");
-
- let output = matches.opt_str("o").map(|s| PathBuf::from(&s));
- let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s));
- let mut cfgs = matches.opt_strs("cfg");
- cfgs.push("rustdoc".to_string());
-
- if let Some(ref p) = css_file_extension {
- if !p.is_file() {
- diag.struct_err("option --extend-css argument must be a file").emit();
- return 1;
- }
- }
-
- let mut themes = Vec::new();
- if matches.opt_present("themes") {
- let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
-
- for (theme_file, theme_s) in matches.opt_strs("themes")
- .iter()
- .map(|s| (PathBuf::from(&s), s.to_owned())) {
- if !theme_file.is_file() {
- diag.struct_err("option --themes arguments must all be files").emit();
- return 1;
- }
- let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
- if !success || !ret.is_empty() {
- diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
- .help("check what's wrong with the --theme-checker option")
- .emit();
- return 1;
- }
- themes.push(theme_file);
- }
- }
-
- let mut id_map = html::markdown::IdMap::new();
- id_map.populate(html::render::initial_ids());
- let external_html = match ExternalHtml::load(
- &matches.opt_strs("html-in-header"),
- &matches.opt_strs("html-before-content"),
- &matches.opt_strs("html-after-content"),
- &matches.opt_strs("markdown-before-content"),
- &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) {
- Some(eh) => eh,
- None => return 3,
- };
- let crate_name = matches.opt_str("crate-name");
- let playground_url = matches.opt_str("playground-url");
- let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
- let display_warnings = matches.opt_present("display-warnings");
- let linker = matches.opt_str("linker").map(PathBuf::from);
- let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
- let resource_suffix = matches.opt_str("resource-suffix");
- let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
- let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
- let enable_minification = !matches.opt_present("disable-minification");
-
- let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
- let edition = match edition.parse() {
- Ok(e) => e,
- Err(_) => {
- diag.struct_err("could not parse edition").emit();
- return 1;
- }
- };
- if let Some(ref index_page) = index_page {
- if !index_page.is_file() {
- diag.struct_err("option `--index-page` argument must be a file").emit();
- return 1;
- }
- }
- let cg = build_codegen_options(&matches, ErrorOutputType::default());
+ let diag = core::new_handler(options.error_format,
+ None,
+ options.debugging_options.treat_err_as_bug,
+ options.debugging_options.ui_testing);
- match (should_test, markdown_input) {
- (true, true) => {
- return markdown::test(&input, cfgs, libs, externs, test_args, maybe_sysroot,
- display_warnings, linker, edition, cg, &diag)
- }
- (true, false) => {
- return test::run(Path::new(&input), cfgs, libs, externs, test_args, crate_name,
- maybe_sysroot, display_warnings, linker, edition, cg)
- }
- (false, true) => return markdown::render(Path::new(&input),
- output.unwrap_or(PathBuf::from("doc")),
- &matches, &external_html,
- !matches.opt_present("markdown-no-toc"), &diag),
+ match (options.should_test, options.markdown_input()) {
+ (true, true) => return markdown::test(options, &diag),
+ (true, false) => return test::run(options),
+ (false, true) => return markdown::render(options.input, options.render_options, &diag),
(false, false) => {}
}
- let output_format = matches.opt_str("w");
-
- let res = acquire_input(PathBuf::from(input), externs, edition, cg, matches, error_format,
- move |out, matches| {
- let Output { krate, passes, renderinfo } = out;
- let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
+ // need to move these items separately because we lose them by the time the closure is called,
+ // but we can't crates the Handler ahead of time because it's not Send
+ let diag_opts = (options.error_format,
+ options.debugging_options.treat_err_as_bug,
+ options.debugging_options.ui_testing);
+ rust_input(options, move |out| {
+ let Output { krate, passes, renderinfo, renderopts } = out;
info!("going to format");
- match output_format.as_ref().map(|s| &**s) {
- Some("html") | None => {
- html::render::run(krate, extern_urls, &external_html, playground_url,
- output.unwrap_or(PathBuf::from("doc")),
- resource_suffix.unwrap_or(String::new()),
- passes.into_iter().collect(),
- css_file_extension,
- renderinfo,
- sort_modules_alphabetically,
- themes,
- enable_minification, id_map,
- enable_index_page, index_page,
- &matches,
- &diag)
- .expect("failed to generate documentation");
- 0
- }
- Some(s) => {
- diag.struct_err(&format!("unknown output format: {}", s)).emit();
- 1
- }
- }
- });
- res.unwrap_or_else(|s| {
- diag.struct_err(&format!("input error: {}", s)).emit();
- 1
+ let (error_format, treat_err_as_bug, ui_testing) = diag_opts;
+ let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing);
+ html::render::run(krate, renderopts, passes.into_iter().collect(), renderinfo, &diag)
+ .expect("failed to generate documentation");
+ 0
})
}
-/// Looks inside the command line arguments to extract the relevant input format
-/// and files and then generates the necessary rustdoc output for formatting.
-fn acquire_input<R, F>(input: PathBuf,
- externs: Externs,
- edition: Edition,
- cg: CodegenOptions,
- matches: getopts::Matches,
- error_format: ErrorOutputType,
- f: F)
- -> Result<R, String>
-where R: 'static + Send, F: 'static + Send + FnOnce(Output, &getopts::Matches) -> R {
- match matches.opt_str("r").as_ref().map(|s| &**s) {
- Some("rust") => Ok(rust_input(input, externs, edition, cg, matches, error_format, f)),
- Some(s) => Err(format!("unknown input format: {}", s)),
- None => Ok(rust_input(input, externs, edition, cg, matches, error_format, f))
- }
-}
-
-/// Extracts `--extern CRATE=PATH` arguments from `matches` and
-/// returns a map mapping crate names to their paths or else an
-/// error message.
-// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
-fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
- let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
- for arg in &matches.opt_strs("extern") {
- let mut parts = arg.splitn(2, '=');
- let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
- let location = parts.next().map(|s| s.to_string());
- if location.is_none() && !nightly_options::is_unstable_enabled(matches) {
- return Err("the `-Z unstable-options` flag must also be passed to \
- enable `--extern crate_name` without `=path`".to_string());
- }
- let name = name.to_string();
- externs.entry(name).or_default().insert(location);
- }
- Ok(Externs::new(externs))
-}
-
-/// Extracts `--extern-html-root-url` arguments from `matches` and returns a map of crate names to
-/// the given URLs. If an `--extern-html-root-url` argument was ill-formed, returns an error
-/// describing the issue.
-fn parse_extern_html_roots(matches: &getopts::Matches)
- -> Result<BTreeMap<String, String>, &'static str>
-{
- let mut externs = BTreeMap::new();
- for arg in &matches.opt_strs("extern-html-root-url") {
- let mut parts = arg.splitn(2, '=');
- let name = parts.next().ok_or("--extern-html-root-url must not be empty")?;
- let url = parts.next().ok_or("--extern-html-root-url must be of the form name=url")?;
- externs.insert(name.to_string(), url.to_string());
- }
-
- Ok(externs)
-}
-
/// Interprets the input file as a rust source file, passing it through the
/// compiler all the way through the analysis passes. The rustdoc output is then
/// generated from the cleaned AST of the crate.
///
/// This form of input will run all of the plug/cleaning passes
-fn rust_input<R, F>(cratefile: PathBuf,
- externs: Externs,
- edition: Edition,
- cg: CodegenOptions,
- matches: getopts::Matches,
- error_format: ErrorOutputType,
- f: F) -> R
+fn rust_input<R, F>(options: config::Options, f: F) -> R
where R: 'static + Send,
- F: 'static + Send + FnOnce(Output, &getopts::Matches) -> R
+ F: 'static + Send + FnOnce(Output) -> R
{
- let default_passes = if matches.opt_present("no-defaults") {
- passes::DefaultPassOption::None
- } else if matches.opt_present("document-private-items") {
- passes::DefaultPassOption::Private
- } else {
- passes::DefaultPassOption::Default
- };
-
- let manual_passes = matches.opt_strs("passes");
- let plugins = matches.opt_strs("plugins");
-
// First, parse the crate and extract all relevant information.
- let mut paths = SearchPaths::new();
- for s in &matches.opt_strs("L") {
- paths.add_path(s, ErrorOutputType::default());
- }
- let mut cfgs = matches.opt_strs("cfg");
- cfgs.push("rustdoc".to_string());
- let triple = matches.opt_str("target").map(|target| {
- if target.ends_with(".json") {
- TargetTriple::TargetPath(PathBuf::from(target))
- } else {
- TargetTriple::TargetTriple(target)
- }
- });
- let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
- let crate_name = matches.opt_str("crate-name");
- let crate_version = matches.opt_str("crate-version");
- let plugin_path = matches.opt_str("plugin-path");
-
info!("starting to run rustc");
- let display_warnings = matches.opt_present("display-warnings");
-
- let force_unstable_if_unmarked = matches.opt_strs("Z").iter().any(|x| {
- *x == "force-unstable-if-unmarked"
- });
- let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
- *x == "treat-err-as-bug"
- });
- let ui_testing = matches.opt_strs("Z").iter().any(|x| {
- *x == "ui-testing"
- });
-
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(&matches, error_format);
let (tx, rx) = channel();
let result = rustc_driver::monitor(move || syntax::with_globals(move || {
- use rustc::session::config::Input;
-
- let (mut krate, renderinfo, passes) =
- core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
- display_warnings, crate_name.clone(),
- force_unstable_if_unmarked, edition, cg, error_format,
- lint_opts, lint_cap, describe_lints, manual_passes, default_passes,
- treat_err_as_bug, ui_testing);
+ let crate_name = options.crate_name.clone();
+ let crate_version = options.crate_version.clone();
+ let (mut krate, renderinfo, renderopts, passes) = core::run_core(options);
info!("finished with rustc");
krate.version = crate_version;
- if !plugins.is_empty() {
- eprintln!("WARNING: --plugins no longer functions; see CVE-2018-1000622");
- }
-
- if !plugin_path.is_none() {
- eprintln!("WARNING: --plugin-path no longer functions; see CVE-2018-1000622");
- }
-
info!("Executing passes");
for pass in &passes {
krate = pass(krate);
}
- tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes },
- &matches)).unwrap();
+ tx.send(f(Output {
+ krate: krate,
+ renderinfo: renderinfo,
+ renderopts,
+ passes: passes
+ })).unwrap();
}));
match result {
Err(_) => panic::resume_unwind(Box::new(errors::FatalErrorMarker)),
}
}
-
-/// Prints deprecation warnings for deprecated options
-fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
- let deprecated_flags = [
- "input-format",
- "output-format",
- "no-defaults",
- "passes",
- ];
-
- for flag in deprecated_flags.into_iter() {
- if matches.opt_present(flag) {
- let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
- flag));
- err.warn("please see https://github.com/rust-lang/rust/issues/44136");
-
- if *flag == "no-defaults" {
- err.help("you may want to use --document-private-items");
- }
-
- err.emit();
- }
- }
-}
use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
-use std::path::{PathBuf, Path};
+use std::path::PathBuf;
use std::cell::RefCell;
use errors;
-use getopts;
use testing;
-use rustc::session::search_paths::SearchPaths;
-use rustc::session::config::{Externs, CodegenOptions};
use syntax::source_map::DUMMY_SP;
use syntax::feature_gate::UnstableFeatures;
-use syntax::edition::Edition;
-use externalfiles::{ExternalHtml, LoadStringError, load_string};
+use externalfiles::{LoadStringError, load_string};
+use config::{Options, RenderOptions};
use html::escape::Escape;
use html::markdown;
use html::markdown::{ErrorCodes, IdMap, Markdown, MarkdownWithToc, find_testable_code};
/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
-pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
- external_html: &ExternalHtml, include_toc: bool, diag: &errors::Handler) -> isize {
+pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> isize {
+ let mut output = options.output;
output.push(input.file_stem().unwrap());
output.set_extension("html");
let mut css = String::new();
- for name in &matches.opt_strs("markdown-css") {
+ for name in &options.markdown_css {
let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
css.push_str(&s)
}
- let input_str = match load_string(input, diag) {
+ let input_str = match load_string(&input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
};
- if let Some(playground) = matches.opt_str("markdown-playground-url").or(
- matches.opt_str("playground-url")) {
+ 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 mut ids = IdMap::new();
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
- let text = if include_toc {
+ let text = if !options.markdown_no_toc {
MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string()
} else {
Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string()
</html>"#,
title = Escape(title),
css = css,
- in_header = external_html.in_header,
- before_content = external_html.before_content,
+ in_header = options.external_html.in_header,
+ before_content = options.external_html.before_content,
text = text,
- after_content = external_html.after_content,
+ after_content = options.external_html.after_content,
);
match err {
}
/// Run any tests/code examples in the markdown file `input`.
-pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
- mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
- display_warnings: bool, linker: Option<PathBuf>, edition: Edition,
- cg: CodegenOptions, diag: &errors::Handler) -> isize {
- let input_str = match load_string(input, diag) {
+pub fn test(mut options: Options, diag: &errors::Handler) -> isize {
+ let input_str = match load_string(&options.input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
- opts.display_warnings = display_warnings;
- let mut collector = Collector::new(input.to_owned(), cfgs, libs, cg, externs,
- true, opts, maybe_sysroot, None,
- Some(PathBuf::from(input)),
- linker, edition);
+ opts.display_warnings = options.display_warnings;
+ let mut collector = Collector::new(options.input.display().to_string(), options.cfgs,
+ options.libs, options.codegen_options, options.externs,
+ true, opts, options.maybe_sysroot, None,
+ Some(options.input),
+ options.linker, options.edition);
collector.set_position(DUMMY_SP);
let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
let res = find_testable_code(&input_str, &mut collector, codes);
if let Err(err) = res {
diag.span_warn(DUMMY_SP, &err.to_string());
}
- test_args.insert(0, "rustdoctest".to_string());
- testing::test_main(&test_args, collector.tests,
- testing::Options::new().display_output(display_warnings));
+ options.test_args.insert(0, "rustdoctest".to_string());
+ testing::test_main(&options.test_args, collector.tests,
+ testing::Options::new().display_output(options.display_warnings));
0
}
use std::ffi::OsString;
use std::io::prelude::*;
use std::io;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
use std::panic::{self, AssertUnwindSafe};
use std::process::Command;
use std::str;
use errors::emitter::ColorConfig;
use clean::Attributes;
+use config::Options;
use html::markdown::{self, ErrorCodes, LangString};
#[derive(Clone, Default)]
pub attrs: Vec<String>,
}
-pub fn run(input_path: &Path,
- cfgs: Vec<String>,
- libs: SearchPaths,
- externs: Externs,
- mut test_args: Vec<String>,
- crate_name: Option<String>,
- maybe_sysroot: Option<PathBuf>,
- display_warnings: bool,
- linker: Option<PathBuf>,
- edition: Edition,
- cg: CodegenOptions)
- -> isize {
- let input = config::Input::File(input_path.to_owned());
+pub fn run(mut options: Options) -> isize {
+ let input = config::Input::File(options.input.clone());
let sessopts = config::Options {
- maybe_sysroot: maybe_sysroot.clone().or_else(
+ maybe_sysroot: options.maybe_sysroot.clone().or_else(
|| Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
- search_paths: libs.clone(),
+ search_paths: options.libs.clone(),
crate_types: vec![config::CrateType::Dylib],
- cg: cg.clone(),
- externs: externs.clone(),
+ cg: options.codegen_options.clone(),
+ externs: options.externs.clone(),
unstable_features: UnstableFeatures::from_environment(),
lint_cap: Some(::rustc::lint::Level::Allow),
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions {
..config::basic_debugging_options()
},
- edition,
+ edition: options.edition,
..config::Options::default()
};
driver::spawn_thread_pool(sessopts, |sessopts| {
Some(source_map.clone()));
let mut sess = session::build_session_(
- sessopts, Some(input_path.to_owned()), handler, source_map.clone(),
+ sessopts, Some(options.input), handler, source_map.clone(),
);
let codegen_backend = rustc_driver::get_codegen_backend(&sess);
let cstore = CStore::new(codegen_backend.metadata_loader());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+ let mut cfg = config::build_configuration(&sess,
+ config::parse_cfgspecs(options.cfgs.clone()));
target_features::add_configuration(&mut cfg, &sess, &*codegen_backend);
sess.parse_sess.config = cfg;
).expect("phase_2_configure_and_expand aborted in rustdoc!")
};
- let crate_name = crate_name.unwrap_or_else(|| {
+ let crate_name = options.crate_name.unwrap_or_else(|| {
::rustc_codegen_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
});
let mut opts = scrape_test_config(hir_forest.krate());
- opts.display_warnings |= display_warnings;
+ opts.display_warnings |= options.display_warnings;
let mut collector = Collector::new(
crate_name,
- cfgs,
- libs,
- cg,
- externs,
+ options.cfgs,
+ options.libs,
+ options.codegen_options,
+ options.externs,
false,
opts,
- maybe_sysroot,
+ options.maybe_sysroot,
Some(source_map),
- None,
- linker,
- edition
+ None,
+ options.linker,
+ options.edition
);
{
});
}
- test_args.insert(0, "rustdoctest".to_string());
+ options.test_args.insert(0, "rustdoctest".to_string());
- testing::test_main(&test_args,
+ testing::test_main(&options.test_args,
collector.tests.into_iter().collect(),
- testing::Options::new().display_output(display_warnings));
+ testing::Options::new().display_output(options.display_warnings));
0
})
}
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
+/// **NOTE**: If a parent of the given path doesn't exist, this function will
+/// return an error. To create a directory and all its missing parents at the
+/// same time, use the [`create_dir_all`] function.
+///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * User lacks permissions to create directory at `path`.
+/// * A parent of the given path doesn't exist. (To create a directory and all
+/// its missing parents at the same time, use the [`create_dir_all`]
+/// function.)
/// * `path` already exists.
///
/// # Examples
#[cfg(target_has_atomic = "64")]
#[unstable(feature = "integer_atomics", issue = "32976")]
impl RefUnwindSafe for atomic::AtomicI64 {}
+#[cfg(all(not(stage0), target_has_atomic = "128"))]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicI128 {}
#[cfg(target_has_atomic = "ptr")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
#[cfg(target_has_atomic = "64")]
#[unstable(feature = "integer_atomics", issue = "32976")]
impl RefUnwindSafe for atomic::AtomicU64 {}
+#[cfg(all(not(stage0), target_has_atomic = "128"))]
+#[unstable(feature = "integer_atomics", issue = "32976")]
+impl RefUnwindSafe for atomic::AtomicU128 {}
#[cfg(target_has_atomic = "8")]
#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
use cell::UnsafeCell;
use fmt;
+use hint;
use mem;
/// A thread local storage key which owns its contents.
// process multiple declarations
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
- __thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
- thread_local!($($rest)*);
+ $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
+ $crate::thread_local!($($rest)*);
);
// handle a single declaration
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
- __thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
+ $crate::__thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
);
}
};
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $init:expr) => {
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
- __thread_local_inner!(@key $(#[$attr])* $vis $name, $t, $init);
+ $crate::__thread_local_inner!(@key $(#[$attr])* $vis $name, $t, $init);
}
}
// operations a little differently and make this safe to call.
mem::replace(&mut *ptr, Some(value));
- (*ptr).as_ref().unwrap()
+ // After storing `Some` we want to get a reference to the contents of
+ // what we just stored. While we could use `unwrap` here and it should
+ // always work it empirically doesn't seem to always get optimized away,
+ // which means that using something like `try_with` can pull in
+ // panicking code and cause a large size bloat.
+ match *ptr {
+ Some(ref x) => x,
+ None => hint::unreachable_unchecked(),
+ }
}
/// Acquires a reference to the value in this TLS key.
}
},
AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
- AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat()?),
+ AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
})
}
}
pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> {
- panictry!(parser.parse_pat())
+ panictry!(parser.parse_pat(None))
}
pub fn parse_arm_panic(parser: &mut Parser) -> Arm {
FatalError.raise();
}
},
- "pat" => token::NtPat(panictry!(p.parse_pat())),
+ "pat" => token::NtPat(panictry!(p.parse_pat(None))),
"expr" => token::NtExpr(panictry!(p.parse_expr())),
"literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())),
"ty" => token::NtTy(panictry!(p.parse_ty())),
(active, abi_thiscall, "1.19.0", None, None),
// Allows a test to fail without failing the whole suite
- (active, allow_fail, "1.19.0", Some(42219), None),
+ (active, allow_fail, "1.19.0", Some(46488), None),
// Allows unsized tuple coercion.
(active, unsized_tuple_coercion, "1.20.0", Some(42877), None),
(active, non_exhaustive, "1.22.0", Some(44109), None),
// `crate` as visibility modifier, synonymous to `pub(crate)`
- (active, crate_visibility_modifier, "1.23.0", Some(45388), None),
+ (active, crate_visibility_modifier, "1.23.0", Some(53120), None),
// extern types
(active, extern_types, "1.23.0", Some(43467), None),
(active, generic_associated_types, "1.23.0", Some(44265), None),
// `extern` in paths
- (active, extern_in_paths, "1.23.0", Some(44660), None),
+ (active, extern_in_paths, "1.23.0", Some(55600), None),
// Use `?` as the Kleene "at most one" operator
(active, macro_at_most_once_rep, "1.25.0", Some(48075), None),
// Infer static outlives requirements; RFC 2093
- (active, infer_static_outlives_requirements, "1.26.0", Some(44493), None),
+ (active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
// Multiple patterns with `|` in `if let` and `while let`
(active, if_while_or_patterns, "1.26.0", Some(48215), None),
// Integer match exhaustiveness checking
(active, exhaustive_integer_patterns, "1.30.0", Some(50907), None),
- // RFC 2070: #[panic_implementation] / #[panic_handler]
- (active, panic_implementation, "1.28.0", Some(44489), None),
-
// #[doc(keyword = "...")]
(active, doc_keyword, "1.28.0", Some(51315), None),
(active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)),
// Support for arbitrary delimited token streams in non-macro attributes
- (active, unrestricted_attribute_tokens, "1.30.0", Some(44690), None),
+ (active, unrestricted_attribute_tokens, "1.30.0", Some(55208), None),
// Allows `use x::y;` to resolve through `self::x`, not just `::x`
(active, uniform_paths, "1.30.0", Some(53130), None),
(active, underscore_const_names, "1.31.0", Some(54912), None),
// `extern crate foo as bar;` puts `bar` into extern prelude.
- (active, extern_crate_item_prelude, "1.31.0", Some(54658), None),
+ (active, extern_crate_item_prelude, "1.31.0", Some(55599), None),
// `reason = ` in lint attributes and `expect` lint attribute
(active, lint_reasons, "1.31.0", Some(54503), None),
Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
(removed, proc_macro_gen, "1.27.0", Some(54727), None,
Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+ (removed, panic_implementation, "1.28.0", Some(44489), None,
+ Some("subsumed by `#[panic_handler]`")),
);
declare_features! (
"infer 'static lifetime requirements",
cfg_fn!(infer_static_outlives_requirements))),
- // RFC 2070 (deprecated attribute name)
- ("panic_implementation",
- Normal,
- Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/44489\
- #issuecomment-415140224",
- Some("replace this attribute with `#[panic_handler]`")),
- "panic_implementation",
- "this attribute was renamed to `panic_handler`",
- cfg_fn!(panic_implementation))),
-
// RFC 2070
("panic_handler", Normal, Ungated),
self.look_ahead(offset + 1, |t| t == &token::Colon)
}
+ /// Skip unexpected attributes and doc comments in this position and emit an appropriate error.
+ fn eat_incorrect_doc_comment(&mut self, applied_to: &str) {
+ if let token::DocComment(_) = self.token {
+ let mut err = self.diagnostic().struct_span_err(
+ self.span,
+ &format!("documentation comments cannot be applied to {}", applied_to),
+ );
+ err.span_label(self.span, "doc comments are not allowed here");
+ err.emit();
+ self.bump();
+ } else if self.token == token::Pound && self.look_ahead(1, |t| {
+ *t == token::OpenDelim(token::Bracket)
+ }) {
+ let lo = self.span;
+ // Skip every token until next possible arg.
+ while self.token != token::CloseDelim(token::Bracket) {
+ self.bump();
+ }
+ let sp = lo.to(self.span);
+ self.bump();
+ let mut err = self.diagnostic().struct_span_err(
+ sp,
+ &format!("attributes cannot be applied to {}", applied_to),
+ );
+ err.span_label(sp, "attributes are not allowed here");
+ err.emit();
+ }
+ }
+
/// This version of parse arg doesn't necessarily require
/// identifier names.
fn parse_arg_general(&mut self, require_name: bool) -> PResult<'a, Arg> {
let (pat, ty) = if require_name || self.is_named_argument() {
debug!("parse_arg_general parse_pat (require_name:{})",
require_name);
- let pat = self.parse_pat()?;
+ self.eat_incorrect_doc_comment("method arguments");
+ let pat = self.parse_pat(Some("argument name"))?;
if let Err(mut err) = self.expect(&token::Colon) {
// If we find a pattern followed by an identifier, it could be an (incorrect)
return Err(err);
}
+ self.eat_incorrect_doc_comment("a method argument's type");
(pat, self.parse_ty()?)
} else {
debug!("parse_arg_general ident_to_pat");
let parser_snapshot_before_ty = self.clone();
+ self.eat_incorrect_doc_comment("a method argument's type");
let mut ty = self.parse_ty();
if ty.is_ok() && self.token == token::Colon {
// This wasn't actually a type, but a pattern looking like a type,
// Recover from attempting to parse the argument as a type without pattern.
err.cancel();
mem::replace(self, parser_snapshot_before_ty);
- let pat = self.parse_pat()?;
+ let pat = self.parse_pat(Some("argument name"))?;
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
/// Parse an argument in a lambda header e.g. |arg, arg|
fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
- let pat = self.parse_pat()?;
+ let pat = self.parse_pat(Some("argument name"))?;
let t = if self.eat(&token::Colon) {
self.parse_ty()?
} else {
return Ok(self.mk_expr(lo.to(hi), ex, attrs));
}
if self.eat_keyword(keywords::Match) {
- return self.parse_match_expr(attrs);
+ let match_sp = self.prev_span;
+ return self.parse_match_expr(attrs).map_err(|mut err| {
+ err.span_label(match_sp, "while parsing this match expression");
+ err
+ });
}
if self.eat_keyword(keywords::Unsafe) {
return self.parse_block_expr(
"`..` can only be used once per tuple or tuple struct pattern");
}
} else if !self.check(&token::CloseDelim(token::Paren)) {
- fields.push(self.parse_pat()?);
+ fields.push(self.parse_pat(None)?);
} else {
break
}
}
}
- let subpat = self.parse_pat()?;
+ let subpat = self.parse_pat(None)?;
if before_slice && self.eat(&token::DotDot) {
slice = Some(subpat);
before_slice = false;
// Parsing a pattern of the form "fieldname: pat"
let fieldname = self.parse_field_name()?;
self.bump();
- let pat = self.parse_pat()?;
+ let pat = self.parse_pat(None)?;
hi = pat.span;
(pat, fieldname, false)
} else {
/// "top-level" patterns in a match arm, `for` loop, `let`, &c. (in contrast
/// to subpatterns within such).
fn parse_top_level_pat(&mut self) -> PResult<'a, P<Pat>> {
- let pat = self.parse_pat()?;
+ let pat = self.parse_pat(None)?;
if self.token == token::Comma {
// An unexpected comma after a top-level pattern is a clue that the
// user (perhaps more accustomed to some other language) forgot the
}
/// Parse a pattern.
- pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> {
- self.parse_pat_with_range_pat(true)
+ pub fn parse_pat(&mut self, expected: Option<&'static str>) -> PResult<'a, P<Pat>> {
+ self.parse_pat_with_range_pat(true, expected)
}
/// Parse a pattern, with a setting whether modern range patterns e.g. `a..=b`, `a..b` are
/// allowed.
- fn parse_pat_with_range_pat(&mut self, allow_range_pat: bool) -> PResult<'a, P<Pat>> {
+ fn parse_pat_with_range_pat(
+ &mut self,
+ allow_range_pat: bool,
+ expected: Option<&'static str>,
+ ) -> PResult<'a, P<Pat>> {
maybe_whole!(self, NtPat, |x| x);
let lo = self.span;
err.span_label(self.span, "unexpected lifetime");
return Err(err);
}
- let subpat = self.parse_pat_with_range_pat(false)?;
+ let subpat = self.parse_pat_with_range_pat(false, expected)?;
pat = PatKind::Ref(subpat, mutbl);
}
token::OpenDelim(token::Paren) => {
pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?;
} else if self.eat_keyword(keywords::Box) {
// Parse box pat
- let subpat = self.parse_pat_with_range_pat(false)?;
+ let subpat = self.parse_pat_with_range_pat(false, None)?;
pat = PatKind::Box(subpat);
} else if self.token.is_ident() && !self.token.is_reserved_ident() &&
self.parse_as_ident() {
}
Err(mut err) => {
self.cancel(&mut err);
- let msg = format!("expected pattern, found {}", self.this_token_descr());
+ let expected = expected.unwrap_or("pattern");
+ let msg = format!(
+ "expected {}, found {}",
+ expected,
+ self.this_token_descr(),
+ );
let mut err = self.fatal(&msg);
- err.span_label(self.span, "expected pattern");
+ err.span_label(self.span, format!("expected {}", expected));
return Err(err);
}
}
-> PResult<'a, PatKind> {
let ident = self.parse_ident()?;
let sub = if self.eat(&token::At) {
- Some(self.parse_pat()?)
+ Some(self.parse_pat(Some("binding pattern"))?)
} else {
None
};
pub fn string_to_pat(source_str: String) -> P<ast::Pat> {
let ps = ParseSess::new(FilePathMapping::empty());
with_error_checking_parse(source_str, &ps, |p| {
- p.parse_pat()
+ p.parse_pat(None)
})
}
pub unsafe fn atomic_i64(x: *mut i64) {
atomic_xadd(x, 1);
}
+#[cfg(target_has_atomic = "128")]
+pub unsafe fn atomic_u128(x: *mut u128) {
+ atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "128")]
+pub unsafe fn atomic_i128(x: *mut i128) {
+ atomic_xadd(x, 1);
+}
#[cfg(target_has_atomic = "ptr")]
pub unsafe fn atomic_usize(x: *mut usize) {
atomic_xadd(x, 1);
$(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg c
wc -c < $(TMPDIR)/foo.wasm
[ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ]
+ $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg d
+ wc -c < $(TMPDIR)/foo.wasm
+ [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ]
else
all:
endif
pub fn foo() {
panic!("{}", "a");
}
+
+#[no_mangle]
+#[cfg(d)]
+pub fn foo() -> usize {
+ use std::cell::Cell;
+ thread_local!(static A: Cell<Vec<u32>> = Cell::new(Vec::new()));
+ A.try_with(|x| x.replace(Vec::new()).len()).unwrap_or(0)
+}
// except according to those terms.
#![crate_type = "cdylib"]
-
-#![feature(panic_implementation)]
#![no_std]
use core::panic::PanicInfo;
panic!()
}
-#[panic_implementation]
+#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(cfg_target_has_atomic)]
+#![feature(integer_atomics)]
+
+use std::mem::{align_of, size_of};
+use std::sync::atomic::*;
+
+fn main() {
+ #[cfg(target_has_atomic = "8")]
+ assert_eq!(align_of::<AtomicBool>(), size_of::<AtomicBool>());
+ #[cfg(target_has_atomic = "ptr")]
+ assert_eq!(align_of::<AtomicPtr<u8>>(), size_of::<AtomicPtr<u8>>());
+ #[cfg(target_has_atomic = "8")]
+ assert_eq!(align_of::<AtomicU8>(), size_of::<AtomicU8>());
+ #[cfg(target_has_atomic = "8")]
+ assert_eq!(align_of::<AtomicI8>(), size_of::<AtomicI8>());
+ #[cfg(target_has_atomic = "16")]
+ assert_eq!(align_of::<AtomicU16>(), size_of::<AtomicU16>());
+ #[cfg(target_has_atomic = "16")]
+ assert_eq!(align_of::<AtomicI16>(), size_of::<AtomicI16>());
+ #[cfg(target_has_atomic = "32")]
+ assert_eq!(align_of::<AtomicU32>(), size_of::<AtomicU32>());
+ #[cfg(target_has_atomic = "32")]
+ assert_eq!(align_of::<AtomicI32>(), size_of::<AtomicI32>());
+ #[cfg(target_has_atomic = "64")]
+ assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
+ #[cfg(target_has_atomic = "64")]
+ assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
+ #[cfg(target_has_atomic = "128")]
+ assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
+ #[cfg(target_has_atomic = "128")]
+ assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
+ #[cfg(target_has_atomic = "ptr")]
+ assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
+ #[cfg(target_has_atomic = "ptr")]
+ assert_eq!(align_of::<AtomicIsize>(), size_of::<AtomicIsize>());
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![no_std]
+
+extern crate std;
+
+std::thread_local!(static A: usize = 30);
+
+fn main() {
+}
3 | no
| ^^ not found in this scope
-thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', librustdoc/test.rs:332:13
+thread '$DIR/failed-doctest-output.rs - OtherStruct (line 27)' panicked at 'couldn't compile the test', librustdoc/test.rs:323:13
note: Run with `RUST_BACKTRACE=1` for a backtrace.
---- $DIR/failed-doctest-output.rs - SomeStruct (line 21) stdout ----
thread 'main' panicked at 'oh no', $DIR/failed-doctest-output.rs:3:1
note: Run with `RUST_BACKTRACE=1` for a backtrace.
-', librustdoc/test.rs:367:17
+', librustdoc/test.rs:358:17
failures:
LL | match x { } //~ ERROR E0004
| ^
|
-help: Please ensure that all possible cases are being handled; possibly adding wildcards or more match arms.
+help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
--> $DIR/E0004-2.rs:14:11
|
LL | match x { } //~ ERROR E0004
-error[E0658]: allow_fail attribute is currently unstable (see issue #42219)
+error[E0658]: allow_fail attribute is currently unstable (see issue #46488)
--> $DIR/feature-gate-allow_fail.rs:13:1
|
LL | #[allow_fail] //~ ERROR allow_fail attribute is currently unstable
pub unsafe fn atomic_i64(x: *mut i64) {
atomic_xadd(x, 1);
}
+#[cfg(target_has_atomic = "128")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_u128(x: *mut u128) {
+ atomic_xadd(x, 1);
+}
+#[cfg(target_has_atomic = "128")]
+//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+pub unsafe fn atomic_i128(x: *mut i128) {
+ atomic_xadd(x, 1);
+}
#[cfg(target_has_atomic = "ptr")]
//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
pub unsafe fn atomic_usize(x: *mut usize) {
//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
cfg!(target_has_atomic = "64");
//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+ cfg!(target_has_atomic = "128");
+ //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
cfg!(target_has_atomic = "ptr");
//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
}
error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
--> $DIR/feature-gate-cfg-target-has-atomic.rs:64:7
|
-LL | #[cfg(target_has_atomic = "ptr")]
+LL | #[cfg(target_has_atomic = "128")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
--> $DIR/feature-gate-cfg-target-has-atomic.rs:69:7
|
+LL | #[cfg(target_has_atomic = "128")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:74:7
+ |
+LL | #[cfg(target_has_atomic = "ptr")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:79:7
+ |
LL | #[cfg(target_has_atomic = "ptr")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
- --> $DIR/feature-gate-cfg-target-has-atomic.rs:76:10
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:86:10
|
LL | cfg!(target_has_atomic = "8");
| ^^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
- --> $DIR/feature-gate-cfg-target-has-atomic.rs:78:10
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:88:10
|
LL | cfg!(target_has_atomic = "16");
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
- --> $DIR/feature-gate-cfg-target-has-atomic.rs:80:10
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:90:10
|
LL | cfg!(target_has_atomic = "32");
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
- --> $DIR/feature-gate-cfg-target-has-atomic.rs:82:10
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:92:10
|
LL | cfg!(target_has_atomic = "64");
| ^^^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
- --> $DIR/feature-gate-cfg-target-has-atomic.rs:84:10
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:94:10
+ |
+LL | cfg!(target_has_atomic = "128");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976)
+ --> $DIR/feature-gate-cfg-target-has-atomic.rs:96:10
|
LL | cfg!(target_has_atomic = "ptr");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable
-error: aborting due to 15 previous errors
+error: aborting due to 18 previous errors
For more information about this error, try `rustc --explain E0658`.
-error[E0658]: `crate` visibility modifier is experimental (see issue #45388)
+error[E0658]: `crate` visibility modifier is experimental (see issue #53120)
--> $DIR/feature-gate-crate_visibility_modifier.rs:11:1
|
LL | crate struct Bender { //~ ERROR `crate` visibility modifier is experimental
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:26:9
|
LL | use alloc;
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:28:9
|
LL | use alloc::boxed;
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:33:11
|
LL | use ::alloc;
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:35:11
|
LL | use ::alloc::boxed;
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:9:17
|
LL | let v = alloc::vec![0];
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:11:18
|
LL | type A = alloc::boxed::Box<u8>;
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:18:19
|
LL | let v = ::alloc::vec![0];
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:20:20
|
LL | type A = ::alloc::boxed::Box<u8>;
|
= help: add #![feature(extern_crate_item_prelude)] to the crate attributes to enable
-error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #54658)
+error[E0658]: use of extern prelude names introduced with `extern crate` items is unstable (see issue #55599)
--> $DIR/feature-gate-extern_crate_item_prelude.rs:42:14
|
LL | type A = core::boxed::Box<u8>;
-error[E0658]: `extern` in paths is experimental (see issue #44660)
+error[E0658]: `extern` in paths is experimental (see issue #55600)
--> $DIR/feature-gate-extern_in_paths.rs:14:13
|
LL | let _ = extern::std::vec::Vec::new(); //~ ERROR `extern` in paths is experimental
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags:-C panic=abort
-
-#![no_std]
-#![no_main]
-
-use core::panic::PanicInfo;
-
-#[panic_implementation] //~ ERROR this attribute was renamed to `panic_handler` (see issue #44489)
-fn panic(info: &PanicInfo) -> ! {
- loop {}
-}
+++ /dev/null
-error[E0658]: this attribute was renamed to `panic_handler` (see issue #44489)
- --> $DIR/feature-gate-panic-implementation.rs:18:1
- |
-LL | #[panic_implementation] //~ ERROR this attribute was renamed to `panic_handler` (see issue #44489)
- | ^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(panic_implementation)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+use NonExistent; //~ ERROR unresolved import `NonExistent`
+use non_existent::non_existent; //~ ERROR unresolved import `non_existent`
+
+#[non_existent] //~ ERROR cannot determine resolution for the attribute macro `non_existent`
+#[derive(NonExistent)] //~ ERROR cannot determine resolution for the derive macro `NonExistent`
+struct S;
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `NonExistent`
+ --> $DIR/issue-55457.rs:1:5
+ |
+LL | use NonExistent; //~ ERROR unresolved import `NonExistent`
+ | ^^^^^^^^^^^ no `NonExistent` in the root. Did you mean to use `non_existent`?
+
+error[E0432]: unresolved import `non_existent`
+ --> $DIR/issue-55457.rs:2:5
+ |
+LL | use non_existent::non_existent; //~ ERROR unresolved import `non_existent`
+ | ^^^^^^^^^^^^ Maybe a missing `extern crate non_existent;`?
+
+error: cannot determine resolution for the derive macro `NonExistent`
+ --> $DIR/issue-55457.rs:5:10
+ |
+LL | #[derive(NonExistent)] //~ ERROR cannot determine resolution for the derive macro `NonExistent`
+ | ^^^^^^^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: cannot determine resolution for the attribute macro `non_existent`
+ --> $DIR/issue-55457.rs:4:3
+ |
+LL | #[non_existent] //~ ERROR cannot determine resolution for the attribute macro `non_existent`
+ | ^^^^^^^^^^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
LL | match () { } //~ ERROR non-exhaustive
| ^^
|
-help: Please ensure that all possible cases are being handled; possibly adding wildcards or more match arms.
+help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
--> $DIR/issue-3096-1.rs:12:11
|
LL | match () { } //~ ERROR non-exhaustive
LL | match x { } //~ ERROR non-exhaustive patterns
| ^
|
-help: Please ensure that all possible cases are being handled; possibly adding wildcards or more match arms.
+help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
--> $DIR/issue-3096-2.rs:15:11
|
LL | match x { } //~ ERROR non-exhaustive patterns
--> $DIR/label_break_value_illegal_uses.rs:28:17
|
LL | match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator
- | ^^ expected one of `.`, `?`, `{`, or an operator here
+ | ----- ^^ expected one of `.`, `?`, `{`, or an operator here
+ | |
+ | while parsing this match expression
error: aborting due to 4 previous errors
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags:-C panic=abort
-
-#![deny(deprecated)]
-#![feature(panic_implementation)]
-#![no_std]
-
-use core::panic::PanicInfo;
-
-#[panic_implementation]
-fn panic(info: &PanicInfo) -> ! {
- loop {}
-}
-
-fn main() {}
+++ /dev/null
-error: use of deprecated attribute `panic_implementation`: this attribute was renamed to `panic_handler`. See https://github.com/rust-lang/rust/issues/44489#issuecomment-415140224
- --> $DIR/panic-implementation-deprecated.rs:19:1
- |
-LL | #[panic_implementation]
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this attribute with `#[panic_handler]`
- |
-note: lint level defined here
- --> $DIR/panic-implementation-deprecated.rs:13:9
- |
-LL | #![deny(deprecated)]
- | ^^^^^^^^^^
-
-error: aborting due to previous error
-
--- /dev/null
+pub fn f(
+ /// Comment
+ //~^ ERROR documentation comments cannot be applied to method arguments
+ //~| NOTE doc comments are not allowed here
+ id: u8,
+ /// Other
+ //~^ ERROR documentation comments cannot be applied to method arguments
+ //~| NOTE doc comments are not allowed here
+ a: u8,
+) {}
+
+fn foo(#[allow(dead_code)] id: i32) {}
+//~^ ERROR attributes cannot be applied to method arguments
+//~| NOTE attributes are not allowed here
+
+fn bar(id: #[allow(dead_code)] i32) {}
+//~^ ERROR attributes cannot be applied to a method argument's type
+//~| NOTE attributes are not allowed here
+
+fn main() {
+ // verify that the parser recovered and properly typechecked the args
+ f("", "");
+ //~^ ERROR mismatched types
+ //~| NOTE expected u8, found reference
+ //~| NOTE expected
+ //~| ERROR mismatched types
+ //~| NOTE expected u8, found reference
+ //~| NOTE expected
+ foo("");
+ //~^ ERROR mismatched types
+ //~| NOTE expected i32, found reference
+ //~| NOTE expected
+ bar("");
+ //~^ ERROR mismatched types
+ //~| NOTE expected i32, found reference
+ //~| NOTE expected
+}
--- /dev/null
+error: documentation comments cannot be applied to method arguments
+ --> $DIR/fn-arg-doc-comment.rs:2:5
+ |
+LL | /// Comment
+ | ^^^^^^^^^^^ doc comments are not allowed here
+
+error: documentation comments cannot be applied to method arguments
+ --> $DIR/fn-arg-doc-comment.rs:6:5
+ |
+LL | /// Other
+ | ^^^^^^^^^ doc comments are not allowed here
+
+error: attributes cannot be applied to method arguments
+ --> $DIR/fn-arg-doc-comment.rs:12:8
+ |
+LL | fn foo(#[allow(dead_code)] id: i32) {}
+ | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
+
+error: attributes cannot be applied to a method argument's type
+ --> $DIR/fn-arg-doc-comment.rs:16:12
+ |
+LL | fn bar(id: #[allow(dead_code)] i32) {}
+ | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here
+
+error[E0308]: mismatched types
+ --> $DIR/fn-arg-doc-comment.rs:22:7
+ |
+LL | f("", "");
+ | ^^ expected u8, found reference
+ |
+ = note: expected type `u8`
+ found type `&'static str`
+
+error[E0308]: mismatched types
+ --> $DIR/fn-arg-doc-comment.rs:22:11
+ |
+LL | f("", "");
+ | ^^ expected u8, found reference
+ |
+ = note: expected type `u8`
+ found type `&'static str`
+
+error[E0308]: mismatched types
+ --> $DIR/fn-arg-doc-comment.rs:29:9
+ |
+LL | foo("");
+ | ^^ expected i32, found reference
+ |
+ = note: expected type `i32`
+ found type `&'static str`
+
+error[E0308]: mismatched types
+ --> $DIR/fn-arg-doc-comment.rs:33:9
+ |
+LL | bar("");
+ | ^^ expected i32, found reference
+ |
+ = note: expected type `i32`
+ found type `&'static str`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
// compile-flags: -Z parse-only
impl S {
- fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*`
+ fn f(*, a: u8) -> u8 {}
+ //~^ ERROR expected argument name, found `*`
}
-error: expected pattern, found `*`
+error: expected argument name, found `*`
--> $DIR/issue-33413.rs:14:10
|
-LL | fn f(*, a: u8) -> u8 {} //~ ERROR expected pattern, found `*`
- | ^ expected pattern
+LL | fn f(*, a: u8) -> u8 {}
+ | ^ expected argument name
error: aborting due to previous error
fn main() {
let foo =
- match
+ match //~ NOTE while parsing this match expression
Some(4).unwrap_or_else(5)
//~^ NOTE expected one of `.`, `?`, `{`, or an operator here
; //~ NOTE unexpected token
error: expected one of `.`, `?`, `{`, or an operator, found `;`
--> $DIR/match-refactor-to-expr.rs:18:9
|
-LL | match
- | ----- help: try removing this `match`
+LL | match //~ NOTE while parsing this match expression
+ | -----
+ | |
+ | while parsing this match expression
+ | help: try removing this `match`
LL | Some(4).unwrap_or_else(5)
| - expected one of `.`, `?`, `{`, or an operator here
LL | //~^ NOTE expected one of `.`, `?`, `{`, or an operator here
// compile-flags: -Z parse-only
-fn f(+x: isize) {} //~ ERROR expected pattern, found `+`
+fn f(+x: isize) {}
+//~^ ERROR expected argument name, found `+`
-error: expected pattern, found `+`
+error: expected argument name, found `+`
--> $DIR/removed-syntax-mode.rs:13:6
|
-LL | fn f(+x: isize) {} //~ ERROR expected pattern, found `+`
- | ^ expected pattern
+LL | fn f(+x: isize) {}
+ | ^ expected argument name
error: aborting due to previous error
--> $DIR/try-block-in-match.rs:16:11
|
LL | match try { false } { _ => {} } //~ ERROR expected expression, found reserved keyword `try`
- | ^^^ expected expression
+ | ----- ^^^ expected expression
+ | |
+ | while parsing this match expression
error: aborting due to previous error
LL | let _ = match x {}; //~ ERROR non-exhaustive
| ^
|
-help: Please ensure that all possible cases are being handled; possibly adding wildcards or more match arms.
+help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
--> $DIR/uninhabited-matches-feature-gated.rs:20:19
|
LL | let _ = match x {}; //~ ERROR non-exhaustive
LL | let _ = match x {}; //~ ERROR non-exhaustive
| ^
|
-help: Please ensure that all possible cases are being handled; possibly adding wildcards or more match arms.
+help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
--> $DIR/uninhabited-matches-feature-gated.rs:23:19
|
LL | let _ = match x {}; //~ ERROR non-exhaustive
LL | let _ = match x {}; //~ ERROR non-exhaustive
| ^
|
-help: Please ensure that all possible cases are being handled; possibly adding wildcards or more match arms.
+help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
--> $DIR/uninhabited-matches-feature-gated.rs:26:19
|
LL | let _ = match x {}; //~ ERROR non-exhaustive