diff --git a/Cargo.lock b/Cargo.lock index 87690718dc05b..2e46d43a79098 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4554,6 +4554,9 @@ dependencies = [ "serde_json", "smallvec 1.6.1", "tempfile", + "tracing", + "tracing-subscriber", + "tracing-tree", ] [[package]] diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 6f98760a7b0ad..a18c1f7452404 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -377,6 +377,18 @@ impl NonConstOp for Panic { } } +/// A call to a `panic()` lang item where the first argument is _not_ a `&str`. +#[derive(Debug)] +pub struct PanicNonStr; +impl NonConstOp for PanicNonStr { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + ccx.tcx.sess.struct_span_err( + span, + "argument to `panic!()` in a const context must have type `&str`", + ) + } +} + #[derive(Debug)] pub struct RawPtrComparison; impl NonConstOp for RawPtrComparison { diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index a82636837122f..2845f27d22bab 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -819,7 +819,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { self.super_terminator(terminator, location); match &terminator.kind { - TerminatorKind::Call { func, .. } => { + TerminatorKind::Call { func, args, .. } => { let ConstCx { tcx, body, param_env, .. } = *self.ccx; let caller = self.def_id().to_def_id(); @@ -881,9 +881,17 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } // At this point, we are calling a function, `callee`, whose `DefId` is known... - if is_lang_panic_fn(tcx, callee) { self.check_op(ops::Panic); + + // const-eval of the `begin_panic` fn assumes the argument is `&str` + if Some(callee) == tcx.lang_items().begin_panic_fn() { + match args[0].ty(&self.ccx.body.local_decls, tcx).kind() { + ty::Ref(_, ty, _) if ty.is_str() => (), + _ => self.check_op(ops::PanicNonStr), + } + } + return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cf08881cd473d..afd1642bbd57c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -544,6 +544,41 @@ impl CheckAttrVisitor<'tcx> { { return false; } + } else if let Some(i_meta) = meta.meta_item() { + if ![ + sym::cfg, + sym::hidden, + sym::html_favicon_url, + sym::html_logo_url, + sym::html_no_source, + sym::html_playground_url, + sym::html_root_url, + sym::include, + sym::inline, + sym::issue_tracker_base_url, + sym::masked, + sym::no_default_passes, // deprecated + sym::no_inline, + sym::passes, // deprecated + sym::primitive, + sym::spotlight, + sym::test, + ] + .iter() + .any(|m| i_meta.has_name(*m)) + { + self.tcx + .sess + .struct_span_err( + meta.span(), + &format!( + "unknown `doc` attribute `{}`", + i_meta.name_or_empty(), + ), + ) + .emit(); + return false; + } } } } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 82f19770a123b..a96f332374430 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1494,12 +1494,13 @@ impl<'tcx> Liveness<'_, 'tcx> { // bindings, and we also consider the first pattern to be the "authoritative" set of ids. // However, we should take the ids and spans of variables with the same name from the later // patterns so the suggestions to prefix with underscores will apply to those too. - let mut vars: FxIndexMap)> = <_>::default(); + let mut vars: FxIndexMap)> = + <_>::default(); pat.each_binding(|_, hir_id, pat_sp, ident| { let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp)); let var = self.variable(hir_id, ident.span); - let id_and_sp = (hir_id, pat_sp); + let id_and_sp = (hir_id, pat_sp, ident.span); vars.entry(self.ir.variable_name(var)) .and_modify(|(.., hir_ids_and_spans)| hir_ids_and_spans.push(id_and_sp)) .or_insert_with(|| (ln, var, vec![id_and_sp])); @@ -1508,7 +1509,8 @@ impl<'tcx> Liveness<'_, 'tcx> { for (_, (ln, var, hir_ids_and_spans)) in vars { if self.used_on_entry(ln, var) { let id = hir_ids_and_spans[0].0; - let spans = hir_ids_and_spans.into_iter().map(|(_, sp)| sp).collect(); + let spans = + hir_ids_and_spans.into_iter().map(|(_, _, ident_span)| ident_span).collect(); on_used_on_entry(spans, id, ln, var); } else { self.report_unused(hir_ids_and_spans, ln, var); @@ -1516,7 +1518,12 @@ impl<'tcx> Liveness<'_, 'tcx> { } } - fn report_unused(&self, hir_ids_and_spans: Vec<(HirId, Span)>, ln: LiveNode, var: Variable) { + fn report_unused( + &self, + hir_ids_and_spans: Vec<(HirId, Span, Span)>, + ln: LiveNode, + var: Variable, + ) { let first_hir_id = hir_ids_and_spans[0].0; if let Some(name) = self.should_warn(var).filter(|name| name != "self") { @@ -1530,7 +1537,10 @@ impl<'tcx> Liveness<'_, 'tcx> { self.ir.tcx.struct_span_lint_hir( lint::builtin::UNUSED_VARIABLES, first_hir_id, - hir_ids_and_spans.into_iter().map(|(_, sp)| sp).collect::>(), + hir_ids_and_spans + .into_iter() + .map(|(_, _, ident_span)| ident_span) + .collect::>(), |lint| { lint.build(&format!("variable `{}` is assigned to, but never used", name)) .note(&format!("consider using `_{}` instead", name)) @@ -1538,54 +1548,67 @@ impl<'tcx> Liveness<'_, 'tcx> { }, ) } else { - self.ir.tcx.struct_span_lint_hir( - lint::builtin::UNUSED_VARIABLES, - first_hir_id, - hir_ids_and_spans.iter().map(|(_, sp)| *sp).collect::>(), - |lint| { - let mut err = lint.build(&format!("unused variable: `{}`", name)); - - let (shorthands, non_shorthands): (Vec<_>, Vec<_>) = - hir_ids_and_spans.into_iter().partition(|(hir_id, span)| { - let var = self.variable(*hir_id, *span); - self.ir.variable_is_shorthand(var) - }); - - let mut shorthands = shorthands - .into_iter() - .map(|(_, span)| (span, format!("{}: _", name))) - .collect::>(); - - // If we have both shorthand and non-shorthand, prefer the "try ignoring - // the field" message, and suggest `_` for the non-shorthands. If we only - // have non-shorthand, then prefix with an underscore instead. - if !shorthands.is_empty() { - shorthands.extend( - non_shorthands - .into_iter() - .map(|(_, span)| (span, "_".to_string())) - .collect::>(), - ); + let (shorthands, non_shorthands): (Vec<_>, Vec<_>) = + hir_ids_and_spans.iter().copied().partition(|(hir_id, _, ident_span)| { + let var = self.variable(*hir_id, *ident_span); + self.ir.variable_is_shorthand(var) + }); + // If we have both shorthand and non-shorthand, prefer the "try ignoring + // the field" message, and suggest `_` for the non-shorthands. If we only + // have non-shorthand, then prefix with an underscore instead. + if !shorthands.is_empty() { + let shorthands = shorthands + .into_iter() + .map(|(_, pat_span, _)| (pat_span, format!("{}: _", name))) + .chain( + non_shorthands + .into_iter() + .map(|(_, pat_span, _)| (pat_span, "_".to_string())), + ) + .collect::>(); + + self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_VARIABLES, + first_hir_id, + hir_ids_and_spans + .iter() + .map(|(_, pat_span, _)| *pat_span) + .collect::>(), + |lint| { + let mut err = lint.build(&format!("unused variable: `{}`", name)); err.multipart_suggestion( "try ignoring the field", shorthands, Applicability::MachineApplicable, ); - } else { + err.emit() + }, + ); + } else { + let non_shorthands = non_shorthands + .into_iter() + .map(|(_, _, ident_span)| (ident_span, format!("_{}", name))) + .collect::>(); + + self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_VARIABLES, + first_hir_id, + hir_ids_and_spans + .iter() + .map(|(_, _, ident_span)| *ident_span) + .collect::>(), + |lint| { + let mut err = lint.build(&format!("unused variable: `{}`", name)); err.multipart_suggestion( "if this is intentional, prefix it with an underscore", - non_shorthands - .into_iter() - .map(|(_, span)| (span, format!("_{}", name))) - .collect::>(), + non_shorthands, Applicability::MachineApplicable, ); - } - - err.emit() - }, - ); + err.emit() + }, + ); + } } } } diff --git a/library/core/src/num/dec2flt/table.rs b/library/core/src/num/dec2flt/table.rs index 1bd94ffa04e0e..97b497e81e070 100644 --- a/library/core/src/num/dec2flt/table.rs +++ b/library/core/src/num/dec2flt/table.rs @@ -5,7 +5,7 @@ pub const MIN_E: i16 = -305; pub const MAX_E: i16 = 305; #[rustfmt::skip] -pub const POWERS: ([u64; 611], [i16; 611]) = ( +pub static POWERS: ([u64; 611], [i16; 611]) = ( [ 0xe0b62e2929aba83c, 0x8c71dcd9ba0b4926, diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 500e8267cf821..31e39b5ad0421 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -23,6 +23,7 @@ pub use crate::sys::windows_ext as windows; pub mod linux; #[cfg(doc)] +#[stable(feature = "wasi_ext_doc", since = "1.35.0")] pub use crate::sys::wasi_ext as wasi; // If we're not documenting libstd then we just expose the main modules as we otherwise would. diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index d3f53801d2d0f..1e79a5c3f9bd5 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -111,7 +111,7 @@ cfg_if::cfg_if! { cfg_if::cfg_if! { if #[cfg(target_os = "wasi")] { // On WASI we'll document what's already available - #[stable(feature = "rust1", since = "1.0.0")] + #[stable(feature = "wasi_ext_doc", since = "1.35.0")] pub use self::ext as wasi_ext; } else if #[cfg(any(target_os = "hermit", target_arch = "wasm32", @@ -125,6 +125,7 @@ cfg_if::cfg_if! { } else { // On other platforms like Windows document the bare bones of WASI #[path = "wasi/ext/mod.rs"] + #[stable(feature = "wasi_ext_doc", since = "1.35.0")] pub mod wasi_ext; } } diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py index 9bbcaf7c4cc49..ad2292e857186 100755 --- a/src/etc/dec2flt_table.py +++ b/src/etc/dec2flt_table.py @@ -113,7 +113,7 @@ def print_proper_powers(): print() print("#[rustfmt::skip]") typ = "([u64; {0}], [i16; {0}])".format(len(powers)) - print("pub const POWERS: ", typ, " = (", sep='') + print("pub static POWERS: ", typ, " = (", sep='') print(" [") for z in powers: print(" 0x{:x},".format(z.sig)) diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1b9a35e649172..44c2c3b17860b 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -19,6 +19,13 @@ tempfile = "3" itertools = "0.9" regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } +tracing = "0.1" +tracing-tree = "0.1.6" + +[dependencies.tracing-subscriber] +version = "0.2.13" +default-features = false +features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] [dev-dependencies] expect-test = "1.0" diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 5cda4cc5ada71..4e4e1e5cbce2f 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { debug!("get_blanket_impls({:?})", ty); let mut impls = Vec::new(); for &trait_def_id in self.cx.tcx.all_traits(LOCAL_CRATE).iter() { - if !self.cx.renderinfo.access_levels.is_public(trait_def_id) + if !self.cx.cache.access_levels.is_public(trait_def_id) || self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some() { continue; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9cfa72132cb5a..47a74238a7a3d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -17,6 +17,7 @@ use rustc_span::Span; use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind}; use crate::core::DocContext; +use crate::formats::item_type::ItemType; use super::Clean; @@ -122,7 +123,7 @@ crate fn try_inline( let target_attrs = load_attrs(cx, did); let attrs = box merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone); - cx.renderinfo.inlined.insert(did); + cx.inlined.insert(did); let what_rustc_thinks = clean::Item::from_def_id_and_parts(did, Some(name), kind, cx); ret.push(clean::Item { attrs, ..what_rustc_thinks }); Some(ret) @@ -181,9 +182,9 @@ crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: clean::Typ }; if did.is_local() { - cx.renderinfo.exact_paths.insert(did, fqn); + cx.cache.exact_paths.insert(did, fqn); } else { - cx.renderinfo.external_paths.insert(did, (fqn, kind)); + cx.cache.external_paths.insert(did, (fqn, ItemType::from(kind))); } } @@ -315,7 +316,7 @@ crate fn build_impl( attrs: Option>, ret: &mut Vec, ) { - if !cx.renderinfo.inlined.insert(did) { + if !cx.inlined.insert(did) { return; } @@ -327,7 +328,7 @@ crate fn build_impl( if !did.is_local() { if let Some(traitref) = associated_trait { let did = traitref.def_id; - if !cx.renderinfo.access_levels.is_public(did) { + if !cx.cache.access_levels.is_public(did) { return; } @@ -359,7 +360,7 @@ crate fn build_impl( // reachable in rustdoc generated documentation if !did.is_local() { if let Some(did) = for_.def_id() { - if !cx.renderinfo.access_levels.is_public(did) { + if !cx.cache.access_levels.is_public(did) { return; } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7aa34333e175d..5d81498f8d210 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1304,7 +1304,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { // Substitute private type aliases if let Some(def_id) = def_id.as_local() { let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); - if !cx.renderinfo.access_levels.is_exported(def_id.to_def_id()) { + if !cx.cache.access_levels.is_exported(def_id.to_def_id()) { alias = Some(&cx.tcx.hir().expect_item(hir_id).kind); } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 7fc48cd5f0b38..09ba0e2740f1b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -50,7 +50,6 @@ thread_local!(crate static MAX_DEF_IDX: RefCell> = #[derive(Clone, Debug)] crate struct Crate { crate name: Symbol, - crate version: Option, crate src: FileName, crate module: Option, crate externs: Vec<(CrateNum, ExternalCrate)>, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 3414bf919401b..a64e8c21c462e 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -17,21 +17,21 @@ use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; -crate fn krate(mut cx: &mut DocContext<'_>) -> Crate { +crate fn krate(cx: &mut DocContext<'_>) -> Crate { use crate::visit_lib::LibEmbargoVisitor; let krate = cx.tcx.hir().krate(); - let module = crate::visit_ast::RustdocVisitor::new(&mut cx).visit(krate); + let module = crate::visit_ast::RustdocVisitor::new(cx).visit(krate); - cx.renderinfo.deref_trait_did = cx.tcx.lang_items().deref_trait(); - cx.renderinfo.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); - cx.renderinfo.owned_box_did = cx.tcx.lang_items().owned_box(); + cx.cache.deref_trait_did = cx.tcx.lang_items().deref_trait(); + cx.cache.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait(); + cx.cache.owned_box_did = cx.tcx.lang_items().owned_box(); let mut externs = Vec::new(); for &cnum in cx.tcx.crates().iter() { externs.push((cnum, cnum.clean(cx))); // Analyze doc-reachability for extern items - LibEmbargoVisitor::new(&mut cx).visit_lib(cnum); + LibEmbargoVisitor::new(cx).visit_lib(cnum); } externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); @@ -77,7 +77,6 @@ crate fn krate(mut cx: &mut DocContext<'_>) -> Crate { Crate { name, - version: None, src, module: Some(module), externs, diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 1478437cefaa3..d9f5b5bfa3ae2 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -4,9 +4,7 @@ use std::ffi::OsStr; use std::fmt; use std::path::PathBuf; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::DefId; -use rustc_middle::middle::privacy::AccessLevels; +use rustc_data_structures::fx::FxHashMap; use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType}; use rustc_session::config::{ build_codegen_options, build_debugging_options, get_cmd_lint_options, host_triple, @@ -268,20 +266,6 @@ crate struct RenderOptions { crate unstable_features: rustc_feature::UnstableFeatures, } -/// Temporary storage for data obtained during `RustdocVisitor::clean()`. -/// Later on moved into `cache`. -#[derive(Default, Clone)] -crate struct RenderInfo { - crate inlined: FxHashSet, - crate external_paths: crate::core::ExternalPaths, - crate exact_paths: FxHashMap>, - crate access_levels: AccessLevels, - crate deref_trait_did: Option, - crate deref_mut_trait_did: Option, - crate owned_box_did: Option, - crate output_format: OutputFormat, -} - 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. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f0b3159f737a6..6218aaf8276d5 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -31,15 +31,12 @@ use std::{cell::RefCell, collections::hash_map::Entry}; use crate::clean; use crate::clean::inline::build_external_trait; use crate::clean::{AttributesExt, TraitWithExtraInfo, MAX_DEF_IDX}; -use crate::config::{Options as RustdocOptions, RenderOptions}; -use crate::config::{OutputFormat, RenderInfo}; +use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions}; use crate::formats::cache::Cache; use crate::passes::{self, Condition::*, ConditionalPass}; crate use rustc_session::config::{DebuggingOptions, Input, Options}; -crate type ExternalPaths = FxHashMap, clean::TypeKind)>; - crate struct DocContext<'tcx> { crate tcx: TyCtxt<'tcx>, /// Name resolver. Used for intra-doc links. @@ -52,8 +49,6 @@ crate struct DocContext<'tcx> { /// /// Most of this logic is copied from rustc_lint::late. crate param_env: ParamEnv<'tcx>, - /// Later on moved into `cache` - crate renderinfo: RenderInfo, /// Later on moved through `clean::Crate` into `cache` crate external_traits: Rc>>, /// Used while populating `external_traits` to ensure we don't process the same trait twice at @@ -81,8 +76,12 @@ crate struct DocContext<'tcx> { /// See `collect_intra_doc_links::traits_implemented_by` for more details. /// `map>` crate module_trait_cache: RefCell>>, - /// Fake empty cache used when cache is required as parameter. + /// This same cache is used throughout rustdoc, including in [`crate::html::render`]. crate cache: Cache, + /// Used by [`clean::inline`] to tell if an item has already been inlined. + crate inlined: FxHashSet, + /// Used by `calculate_doc_coverage`. + crate output_format: OutputFormat, } impl<'tcx> DocContext<'tcx> { @@ -465,7 +464,7 @@ crate fn run_global_ctxt( mut manual_passes: Vec, render_options: RenderOptions, output_format: OutputFormat, -) -> (clean::Crate, RenderInfo, RenderOptions) { +) -> (clean::Crate, RenderOptions, Cache) { // Certain queries assume that some checks were run elsewhere // (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425), // so type-check everything other than function bodies in this crate before running lints. @@ -492,6 +491,7 @@ crate fn run_global_ctxt( tcx.ensure().check_mod_attrs(module); } }); + rustc_passes::stability::check_unused_or_stable_features(tcx); let access_levels = tcx.privacy_access_levels(LOCAL_CRATE); // Convert from a HirId set to a DefId set since we don't always have easy access @@ -504,17 +504,12 @@ crate fn run_global_ctxt( .collect(), }; - let mut renderinfo = RenderInfo::default(); - renderinfo.access_levels = access_levels; - renderinfo.output_format = output_format; - let mut ctxt = DocContext { tcx, resolver, param_env: ParamEnv::empty(), external_traits: Default::default(), active_extern_traits: Default::default(), - renderinfo, ty_substs: Default::default(), lt_substs: Default::default(), ct_substs: Default::default(), @@ -527,9 +522,11 @@ crate fn run_global_ctxt( .cloned() .filter(|trait_def_id| tcx.trait_is_auto(*trait_def_id)) .collect(), - render_options, module_trait_cache: RefCell::new(FxHashMap::default()), - cache: Cache::default(), + cache: Cache::new(access_levels, render_options.document_private), + inlined: FxHashSet::default(), + output_format, + render_options, }; // Small hack to force the Sized trait to be present. @@ -647,10 +644,16 @@ crate fn run_global_ctxt( ctxt.sess().abort_if_errors(); + let render_options = ctxt.render_options; + let mut cache = ctxt.cache; + krate = tcx.sess.time("create_format_cache", || { + cache.populate(krate, tcx, &render_options.extern_html_root_urls, &render_options.output) + }); + // The main crate doc comments are always collapsed. krate.collapsed = true; - (krate, ctxt.renderinfo, ctxt.render_options) + (krate, render_options, cache) } /// Due to , diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index e9c5dd50d59a8..f20296f4fe148 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -11,7 +11,6 @@ use rustc_span::symbol::sym; use rustc_span::Symbol; use crate::clean::{self, GetDefId}; -use crate::config::RenderInfo; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; @@ -131,44 +130,23 @@ struct CacheBuilder<'a, 'tcx> { } impl Cache { - crate fn from_krate<'tcx>( - render_info: RenderInfo, - document_private: bool, + crate fn new(access_levels: AccessLevels, document_private: bool) -> Self { + Cache { access_levels, document_private, ..Cache::default() } + } + + /// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was + /// in `krate` due to the data being moved into the `Cache`. + crate fn populate( + &mut self, + mut krate: clean::Crate, + tcx: TyCtxt<'_>, extern_html_root_urls: &BTreeMap, dst: &Path, - mut krate: clean::Crate, - tcx: TyCtxt<'tcx>, - ) -> (clean::Crate, Cache) { + ) -> clean::Crate { // Crawl the crate to build various caches used for the output - let RenderInfo { - inlined: _, - external_paths, - exact_paths, - access_levels, - deref_trait_did, - deref_mut_trait_did, - owned_box_did, - .. - } = render_info; - - let external_paths = - external_paths.into_iter().map(|(k, (v, t))| (k, (v, ItemType::from(t)))).collect(); - - let mut cache = Cache { - external_paths, - exact_paths, - parent_is_trait_impl: false, - stripped_mod: false, - access_levels, - crate_version: krate.version.take(), - document_private, - traits: krate.external_traits.replace(Default::default()), - deref_trait_did, - deref_mut_trait_did, - owned_box_did, - masked_crates: mem::take(&mut krate.masked_crates), - ..Cache::default() - }; + debug!(?self.crate_version); + self.traits = krate.external_traits.take(); + self.masked_crates = mem::take(&mut krate.masked_crates); // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code @@ -181,12 +159,11 @@ impl Cache { _ => PathBuf::new(), }; let extern_url = extern_html_root_urls.get(&*e.name.as_str()).map(|u| &**u); - cache - .extern_locations + self.extern_locations .insert(n, (e.name, src_root, extern_location(e, extern_url, &dst))); let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - cache.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); + self.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); } // Cache where all known primitives have their documentation located. @@ -195,27 +172,26 @@ impl Cache { // reverse topological order. for &(_, ref e) in krate.externs.iter().rev() { for &(def_id, prim) in &e.primitives { - cache.primitive_locations.insert(prim, def_id); + self.primitive_locations.insert(prim, def_id); } } for &(def_id, prim) in &krate.primitives { - cache.primitive_locations.insert(prim, def_id); + self.primitive_locations.insert(prim, def_id); } - cache.stack.push(krate.name.to_string()); + self.stack.push(krate.name.to_string()); - krate = CacheBuilder { tcx, cache: &mut cache, empty_cache: Cache::default() } - .fold_crate(krate); + krate = CacheBuilder { tcx, cache: self, empty_cache: Cache::default() }.fold_crate(krate); - for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) { - if cache.traits.contains_key(&trait_did) { + for (trait_did, dids, impl_) in self.orphan_trait_impls.drain(..) { + if self.traits.contains_key(&trait_did) { for did in dids { - cache.impls.entry(did).or_default().push(impl_.clone()); + self.impls.entry(did).or_default().push(impl_.clone()); } } } - (krate, cache) + krate } } diff --git a/src/librustdoc/formats/renderer.rs b/src/librustdoc/formats/renderer.rs index 6437ba45511a1..b779363e5c701 100644 --- a/src/librustdoc/formats/renderer.rs +++ b/src/librustdoc/formats/renderer.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::edition::Edition; use crate::clean; -use crate::config::{RenderInfo, RenderOptions}; +use crate::config::RenderOptions; use crate::error::Error; use crate::formats::cache::Cache; @@ -18,7 +18,6 @@ crate trait FormatRenderer<'tcx>: Clone { fn init( krate: clean::Crate, options: RenderOptions, - render_info: RenderInfo, edition: Edition, cache: Cache, tcx: TyCtxt<'tcx>, @@ -49,26 +48,16 @@ crate trait FormatRenderer<'tcx>: Clone { crate fn run_format<'tcx, T: FormatRenderer<'tcx>>( krate: clean::Crate, options: RenderOptions, - render_info: RenderInfo, + cache: Cache, diag: &rustc_errors::Handler, edition: Edition, tcx: TyCtxt<'tcx>, ) -> Result<(), Error> { - let (krate, cache) = tcx.sess.time("create_format_cache", || { - Cache::from_krate( - render_info.clone(), - options.document_private, - &options.extern_html_root_urls, - &options.output, - krate, - tcx, - ) - }); let prof = &tcx.sess.prof; let (mut format_renderer, mut krate) = prof .extra_verbose_generic_activity("create_renderer", T::descr()) - .run(|| T::init(krate, options, render_info, edition, cache, tcx))?; + .run(|| T::init(krate, options, edition, cache, tcx))?; let mut item = match krate.module.take() { Some(i) => i, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 58e9e41e6a53c..4e762a40f0849 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -66,7 +66,7 @@ use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; use crate::clean::{self, AttributesExt, GetDefId, RenderedLink, SelfTy, TypeKind}; -use crate::config::{RenderInfo, RenderOptions}; +use crate::config::RenderOptions; use crate::docfs::{DocFS, PathError}; use crate::error::Error; use crate::formats::cache::Cache; @@ -385,7 +385,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { fn init( mut krate: clean::Crate, options: RenderOptions, - _render_info: RenderInfo, edition: Edition, mut cache: Cache, tcx: TyCtxt<'tcx>, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index a3b214677941b..e6edf33d23c8d 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -19,7 +19,7 @@ use rustc_span::edition::Edition; use rustdoc_json_types as types; use crate::clean; -use crate::config::{RenderInfo, RenderOptions}; +use crate::config::RenderOptions; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer; @@ -133,7 +133,6 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { fn init( krate: clean::Crate, options: RenderOptions, - _render_info: RenderInfo, _edition: Edition, cache: Cache, tcx: TyCtxt<'tcx>, @@ -200,7 +199,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { fn after_krate( &mut self, - krate: &clean::Crate, + _krate: &clean::Crate, _diag: &rustc_errors::Handler, ) -> Result<(), Error> { debug!("Done with crate"); @@ -211,7 +210,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { #[allow(rustc::default_hash_types)] let output = types::Crate { root: types::Id(String::from("0:0")), - crate_version: krate.version.clone(), + crate_version: self.cache.crate_version.clone(), includes_private: self.cache.document_private, index: index.into_iter().collect(), paths: self diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2342ed3ab670d..6b37643a39580 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -49,6 +49,7 @@ extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_mir; extern crate rustc_parse; +extern crate rustc_passes; extern crate rustc_resolve; extern crate rustc_session; extern crate rustc_span as rustc_span; @@ -94,7 +95,19 @@ mod visit_lib; pub fn main() { rustc_driver::set_sigpipe_handler(); rustc_driver::install_ice_hook(); + + // When using CI artifacts (with `download_stage1 = true`), tracing is unconditionally built + // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid + // this, compile our own version of `tracing` that logs all levels. + // NOTE: this compiles both versions of tracing unconditionally, because + // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and + // - Otherwise, there's no warning that logging is being ignored when `download_stage1 = true`. + // NOTE: The reason this doesn't show double logging when `download_stage1 = false` and + // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one + // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml). + init_logging(); rustc_driver::init_env_logger("RUSTDOC_LOG"); + let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() { Some(args) => main_args(&args), _ => Err(ErrorReported), @@ -102,6 +115,68 @@ pub fn main() { process::exit(exit_code); } +fn init_logging() { + use std::io; + + // FIXME remove these and use winapi 0.3 instead + // Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs, rustc_driver/lib.rs + #[cfg(unix)] + fn stdout_isatty() -> bool { + extern crate libc; + unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } + } + + #[cfg(windows)] + fn stdout_isatty() -> bool { + extern crate winapi; + use winapi::um::consoleapi::GetConsoleMode; + use winapi::um::processenv::GetStdHandle; + use winapi::um::winbase::STD_OUTPUT_HANDLE; + + unsafe { + let handle = GetStdHandle(STD_OUTPUT_HANDLE); + let mut out = 0; + GetConsoleMode(handle, &mut out) != 0 + } + } + + let color_logs = match std::env::var("RUSTDOC_LOG_COLOR") { + Ok(value) => match value.as_ref() { + "always" => true, + "never" => false, + "auto" => stdout_isatty(), + _ => early_error( + ErrorOutputType::default(), + &format!( + "invalid log color value '{}': expected one of always, never, or auto", + value + ), + ), + }, + Err(std::env::VarError::NotPresent) => stdout_isatty(), + Err(std::env::VarError::NotUnicode(_value)) => early_error( + ErrorOutputType::default(), + "non-Unicode log color value: expected one of always, never, or auto", + ), + }; + let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG"); + let layer = tracing_tree::HierarchicalLayer::default() + .with_writer(io::stderr) + .with_indent_lines(true) + .with_ansi(color_logs) + .with_targets(true) + .with_wraparound(10) + .with_verbose_exit(true) + .with_verbose_entry(true) + .with_indent_amount(2); + #[cfg(parallel_compiler)] + let layer = layer.with_thread_ids(true).with_thread_names(true); + + use tracing_subscriber::layer::SubscriberExt; + let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); + tracing::subscriber::set_global_default(subscriber).unwrap(); +} + fn get_args() -> Option> { env::args_os() .enumerate() @@ -479,12 +554,12 @@ fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainRes fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( krate: clean::Crate, renderopts: config::RenderOptions, - render_info: config::RenderInfo, + cache: formats::cache::Cache, diag: &rustc_errors::Handler, edition: rustc_span::edition::Edition, tcx: TyCtxt<'tcx>, ) -> MainResult { - match formats::run_format::(krate, renderopts, render_info, &diag, edition, tcx) { + match formats::run_format::(krate, renderopts, cache, &diag, edition, tcx) { Ok(_) => Ok(()), Err(e) => { let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error)); @@ -553,7 +628,7 @@ fn main_options(options: config::Options) -> MainResult { let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut(); global_ctxt.enter(|tcx| { - let (mut krate, render_info, render_opts) = sess.time("run_global_ctxt", || { + let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { core::run_global_ctxt( tcx, resolver, @@ -565,7 +640,7 @@ fn main_options(options: config::Options) -> MainResult { }); info!("finished with rustc"); - krate.version = crate_version; + cache.crate_version = crate_version; if show_coverage { // if we ran coverage, bail early, we don't need to also generate docs at this point @@ -584,7 +659,7 @@ fn main_options(options: config::Options) -> MainResult { run_renderer::>( krate, render_opts, - render_info, + cache, &diag, edition, tcx, @@ -594,7 +669,7 @@ fn main_options(options: config::Options) -> MainResult { run_renderer::>( krate, render_opts, - render_info, + cache, &diag, edition, tcx, diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index c3365b844ecb8..bb54523871c3e 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -127,7 +127,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { } fn print_results(&self) { - let output_format = self.ctx.renderinfo.output_format; + let output_format = self.ctx.output_format; if output_format.is_json() { println!("{}", self.to_json()); return; diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 0e84a51017761..685451b87eda9 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -47,7 +47,7 @@ crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate { // FIXME(eddyb) is this `doc(hidden)` check needed? if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { let impls = get_auto_trait_and_blanket_impls(cx, def_id); - new_items.extend(impls.filter(|i| cx.renderinfo.inlined.insert(i.def_id))); + new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id))); } }); } diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index e8e1bead84fb6..3b1508c134857 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -97,7 +97,7 @@ crate fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { |lint| lint.build("missing code example in this documentation").emit(), ); } - } else if tests.found_tests > 0 && !cx.renderinfo.access_levels.is_public(item.def_id) { + } else if tests.found_tests > 0 && !cx.cache.access_levels.is_public(item.def_id) { cx.tcx.struct_span_lint_hir( lint::builtin::PRIVATE_DOC_TESTS, hir_id, diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index f83eab6799ee6..fc8bbc9715029 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -17,13 +17,12 @@ crate const STRIP_PRIVATE: Pass = Pass { crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = DefIdSet::default(); - let access_levels = cx.renderinfo.access_levels.clone(); // strip all private items { let mut stripper = Stripper { retained: &mut retained, - access_levels: &access_levels, + access_levels: &cx.cache.access_levels, update_retained: true, }; krate = ImportStripper.fold_crate(stripper.fold_crate(krate)); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4d42c181d8cf2..5da7d2f1e9b84 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { assert_eq!(cur_mod_def_id, macro_parent_def_id); cur_mod.macros.push((def, None)); } - self.cx.renderinfo.exact_paths = self.exact_paths; + self.cx.cache.exact_paths = self.exact_paths; top_level_module } @@ -199,7 +199,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } else { // All items need to be handled here in case someone wishes to link // to them with intra-doc links - self.cx.renderinfo.access_levels.map.insert(did, AccessLevel::Public); + self.cx.cache.access_levels.map.insert(did, AccessLevel::Public); } } } @@ -211,7 +211,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { None => return false, }; - let is_private = !self.cx.renderinfo.access_levels.is_public(res_did); + let is_private = !self.cx.cache.access_levels.is_public(res_did); let is_hidden = inherits_doc_hidden(self.cx, res_hir_id); // Only inline if requested or if the item would otherwise be stripped. diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index daed5bd107db1..3e06b4173144c 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { crate fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> { LibEmbargoVisitor { tcx: cx.tcx, - access_levels: &mut cx.renderinfo.access_levels, + access_levels: &mut cx.cache.access_levels, prev_level: Some(AccessLevel::Public), visited_mods: FxHashSet::default(), } diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index a3d4935f49614..5bb66f7f6fd7c 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -1,6 +1,8 @@ // edition:2018 +// compile-flags: --crate-version 1.0.0 -// @is nested.json "$.index[*][?(@.name=='nested')].kind" \"module\" +// @is nested.json "$.crate_version" \"1.0.0\" +// @is - "$.index[*][?(@.name=='nested')].kind" \"module\" // @is - "$.index[*][?(@.name=='nested')].inner.is_crate" true // @count - "$.index[*][?(@.name=='nested')].inner.items[*]" 1 diff --git a/src/test/rustdoc-ui/deprecated-attrs.rs b/src/test/rustdoc-ui/deprecated-attrs.rs index 0d5dfa733fab6..ca626afbe5359 100644 --- a/src/test/rustdoc-ui/deprecated-attrs.rs +++ b/src/test/rustdoc-ui/deprecated-attrs.rs @@ -1,6 +1,6 @@ // check-pass -#![doc(no_default_passes, passes = "collapse-docs unindent-comments")] +#![doc(no_default_passes, passes = "unindent-comments")] struct SomeStruct; diff --git a/src/test/rustdoc-ui/doc-attr.rs b/src/test/rustdoc-ui/doc-attr.rs new file mode 100644 index 0000000000000..37c69a214b8ed --- /dev/null +++ b/src/test/rustdoc-ui/doc-attr.rs @@ -0,0 +1,5 @@ +#![crate_type = "lib"] +#![doc(as_ptr)] //~ ERROR + +#[doc(as_ptr)] //~ ERROR +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc-attr.stderr b/src/test/rustdoc-ui/doc-attr.stderr new file mode 100644 index 0000000000000..17bc3d6a45a05 --- /dev/null +++ b/src/test/rustdoc-ui/doc-attr.stderr @@ -0,0 +1,14 @@ +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr.rs:4:7 + | +LL | #[doc(as_ptr)] + | ^^^^^^ + +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr.rs:2:8 + | +LL | #![doc(as_ptr)] + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc-ui/rustc-check-passes.rs b/src/test/rustdoc-ui/rustc-check-passes.rs new file mode 100644 index 0000000000000..731cc8ba61750 --- /dev/null +++ b/src/test/rustdoc-ui/rustc-check-passes.rs @@ -0,0 +1,4 @@ +#![feature(box_syntax)] +#![feature(box_syntax)] //~ ERROR + +pub fn foo() {} diff --git a/src/test/rustdoc-ui/rustc-check-passes.stderr b/src/test/rustdoc-ui/rustc-check-passes.stderr new file mode 100644 index 0000000000000..9707895ff3dfe --- /dev/null +++ b/src/test/rustdoc-ui/rustc-check-passes.stderr @@ -0,0 +1,9 @@ +error[E0636]: the feature `box_syntax` has already been declared + --> $DIR/rustc-check-passes.rs:2:12 + | +LL | #![feature(box_syntax)] + | ^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0636`. diff --git a/src/test/rustdoc/implementor-stable-version.rs b/src/test/rustdoc/implementor-stable-version.rs index 0a065d8095bf2..a1f3fd5a8c5af 100644 --- a/src/test/rustdoc/implementor-stable-version.rs +++ b/src/test/rustdoc/implementor-stable-version.rs @@ -1,3 +1,4 @@ +#![stable(feature = "bar", since = "OLD 1.0")] #![crate_name = "foo"] #![feature(staged_api)] @@ -8,6 +9,7 @@ pub trait Bar {} #[stable(feature = "baz", since = "OLD 1.0")] pub trait Baz {} +#[stable(feature = "baz", since = "OLD 1.0")] pub struct Foo; // @has foo/trait.Bar.html '//div[@id="implementors-list"]//span[@class="since"]' 'NEW 2.0' diff --git a/src/test/ui/attributes/doc-attr.rs b/src/test/ui/attributes/doc-attr.rs new file mode 100644 index 0000000000000..37c69a214b8ed --- /dev/null +++ b/src/test/ui/attributes/doc-attr.rs @@ -0,0 +1,5 @@ +#![crate_type = "lib"] +#![doc(as_ptr)] //~ ERROR + +#[doc(as_ptr)] //~ ERROR +pub fn foo() {} diff --git a/src/test/ui/attributes/doc-attr.stderr b/src/test/ui/attributes/doc-attr.stderr new file mode 100644 index 0000000000000..17bc3d6a45a05 --- /dev/null +++ b/src/test/ui/attributes/doc-attr.stderr @@ -0,0 +1,14 @@ +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr.rs:4:7 + | +LL | #[doc(as_ptr)] + | ^^^^^^ + +error: unknown `doc` attribute `as_ptr` + --> $DIR/doc-attr.rs:2:8 + | +LL | #![doc(as_ptr)] + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.rs b/src/test/ui/consts/issue-66693-panic-in-array-len.rs new file mode 100644 index 0000000000000..718a19067a6ac --- /dev/null +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.rs @@ -0,0 +1,17 @@ +// This is a separate test from `issue-66693.rs` because array lengths are evaluated +// in a separate stage before `const`s and `statics` and so the error below is hit and +// the compiler exits before generating errors for the others. + +#![feature(const_panic)] + +fn main() { + let _ = [0i32; panic!(2f32)]; + //~^ ERROR: argument to `panic!()` in a const context must have type `&str` + + // ensure that conforming panics are handled correctly + let _ = [false; panic!()]; + //~^ ERROR: evaluation of constant value failed + + // typechecking halts before getting to this one + let _ = ['a', panic!("panic in array len")]; +} diff --git a/src/test/ui/consts/issue-66693-panic-in-array-len.stderr b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr new file mode 100644 index 0000000000000..e0ca9dfde0bf9 --- /dev/null +++ b/src/test/ui/consts/issue-66693-panic-in-array-len.stderr @@ -0,0 +1,19 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693-panic-in-array-len.rs:8:20 + | +LL | let _ = [0i32; panic!(2f32)]; + | ^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-66693-panic-in-array-len.rs:12:21 + | +LL | let _ = [false; panic!()]; + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/issue-66693-panic-in-array-len.rs:12:21 + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/issue-66693.rs b/src/test/ui/consts/issue-66693.rs new file mode 100644 index 0000000000000..77fe4417d5b10 --- /dev/null +++ b/src/test/ui/consts/issue-66693.rs @@ -0,0 +1,24 @@ +// Tests that the compiler does not ICE when const-evaluating a `panic!()` invocation with a +// non-`&str` argument. + +#![feature(const_panic)] + +const _: () = panic!(1); +//~^ ERROR: argument to `panic!()` in a const context must have type `&str` + +static _FOO: () = panic!(true); +//~^ ERROR: argument to `panic!()` in a const context must have type `&str` + +const fn _foo() { + panic!(&1); //~ ERROR: argument to `panic!()` in a const context must have type `&str` +} + +// ensure that conforming panics don't cause an error +const _: () = panic!(); +static _BAR: () = panic!("panic in static"); + +const fn _bar() { + panic!("panic in const fn"); +} + +fn main() {} diff --git a/src/test/ui/consts/issue-66693.stderr b/src/test/ui/consts/issue-66693.stderr new file mode 100644 index 0000000000000..6bbde057ead7f --- /dev/null +++ b/src/test/ui/consts/issue-66693.stderr @@ -0,0 +1,26 @@ +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:13:5 + | +LL | panic!(&1); + | ^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:6:15 + | +LL | const _: () = panic!(1); + | ^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: argument to `panic!()` in a const context must have type `&str` + --> $DIR/issue-66693.rs:9:19 + | +LL | static _FOO: () = panic!(true); + | ^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/consts/issue-76064.rs b/src/test/ui/consts/issue-76064.rs index 2da764b47c0c4..d511f75df8129 100644 --- a/src/test/ui/consts/issue-76064.rs +++ b/src/test/ui/consts/issue-76064.rs @@ -1,3 +1,5 @@ -struct Bug([u8; panic!(1)]); //~ ERROR panicking in constants is unstable +// Note: non-`&str` panic arguments gained a separate error in PR #80734 +// which is why this doesn't match the issue +struct Bug([u8; panic!("panic")]); //~ ERROR panicking in constants is unstable fn main() {} diff --git a/src/test/ui/consts/issue-76064.stderr b/src/test/ui/consts/issue-76064.stderr index f939ff3397504..9bda1b7570d56 100644 --- a/src/test/ui/consts/issue-76064.stderr +++ b/src/test/ui/consts/issue-76064.stderr @@ -1,8 +1,8 @@ error[E0658]: panicking in constants is unstable - --> $DIR/issue-76064.rs:1:17 + --> $DIR/issue-76064.rs:3:17 | -LL | struct Bug([u8; panic!(1)]); - | ^^^^^^^^^ +LL | struct Bug([u8; panic!("panic")]); + | ^^^^^^^^^^^^^^^ | = note: see issue #51999 for more information = help: add `#![feature(const_panic)]` to the crate attributes to enable diff --git a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr index 3efd87f6a5f11..2ef655efdbdf0 100644 --- a/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr +++ b/src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr @@ -12,16 +12,16 @@ LL | #![warn(unused)] // UI tests pass `-A unused` (#43896) = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` warning: unused variable: `mut_unused_var` - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:33:9 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:33:13 | LL | let mut mut_unused_var = 1; - | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_mut_unused_var` + | ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_mut_unused_var` warning: unused variable: `var` - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:10 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:14 | LL | let (mut var, unused_var) = (1, 2); - | ^^^^^^^ help: if this is intentional, prefix it with an underscore: `_var` + | ^^^ help: if this is intentional, prefix it with an underscore: `_var` warning: unused variable: `unused_var` --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:37:19 @@ -36,10 +36,10 @@ LL | if let SoulHistory { corridors_of_light, | ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _` warning: variable `hours_are_suns` is assigned to, but never used - --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:46:26 + --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:46:30 | LL | mut hours_are_suns, - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = note: consider using `_hours_are_suns` instead diff --git a/src/test/ui/lint/issue-81314-unused-span-ident.fixed b/src/test/ui/lint/issue-81314-unused-span-ident.fixed new file mode 100644 index 0000000000000..aac918f2bc817 --- /dev/null +++ b/src/test/ui/lint/issue-81314-unused-span-ident.fixed @@ -0,0 +1,12 @@ +// run-rustfix +// Regression test for #81314: Unused variable lint should +// span only the identifier and not the rest of the pattern + +#![deny(unused)] + +fn main() { + let [_rest @ ..] = [1, 2, 3]; //~ ERROR unused variable +} + +pub fn foo([_rest @ ..]: &[i32]) { //~ ERROR unused variable +} diff --git a/src/test/ui/lint/issue-81314-unused-span-ident.rs b/src/test/ui/lint/issue-81314-unused-span-ident.rs new file mode 100644 index 0000000000000..78296f4258d73 --- /dev/null +++ b/src/test/ui/lint/issue-81314-unused-span-ident.rs @@ -0,0 +1,12 @@ +// run-rustfix +// Regression test for #81314: Unused variable lint should +// span only the identifier and not the rest of the pattern + +#![deny(unused)] + +fn main() { + let [rest @ ..] = [1, 2, 3]; //~ ERROR unused variable +} + +pub fn foo([rest @ ..]: &[i32]) { //~ ERROR unused variable +} diff --git a/src/test/ui/lint/issue-81314-unused-span-ident.stderr b/src/test/ui/lint/issue-81314-unused-span-ident.stderr new file mode 100644 index 0000000000000..519c71e941311 --- /dev/null +++ b/src/test/ui/lint/issue-81314-unused-span-ident.stderr @@ -0,0 +1,21 @@ +error: unused variable: `rest` + --> $DIR/issue-81314-unused-span-ident.rs:8:10 + | +LL | let [rest @ ..] = [1, 2, 3]; + | ^^^^ help: if this is intentional, prefix it with an underscore: `_rest` + | +note: the lint level is defined here + --> $DIR/issue-81314-unused-span-ident.rs:5:9 + | +LL | #![deny(unused)] + | ^^^^^^ + = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]` + +error: unused variable: `rest` + --> $DIR/issue-81314-unused-span-ident.rs:11:13 + | +LL | pub fn foo([rest @ ..]: &[i32]) { + | ^^^^ help: if this is intentional, prefix it with an underscore: `_rest` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/liveness/liveness-consts.stderr b/src/test/ui/liveness/liveness-consts.stderr index fa8a590a819d1..b1beec97df568 100644 --- a/src/test/ui/liveness/liveness-consts.stderr +++ b/src/test/ui/liveness/liveness-consts.stderr @@ -1,8 +1,8 @@ warning: variable `a` is assigned to, but never used - --> $DIR/liveness-consts.rs:7:9 + --> $DIR/liveness-consts.rs:7:13 | LL | let mut a = 0; - | ^^^^^ + | ^ | note: the lint level is defined here --> $DIR/liveness-consts.rs:2:9 diff --git a/src/test/ui/liveness/liveness-dead.stderr b/src/test/ui/liveness/liveness-dead.stderr index e9d20cf981fbd..12680ab11568f 100644 --- a/src/test/ui/liveness/liveness-dead.stderr +++ b/src/test/ui/liveness/liveness-dead.stderr @@ -1,8 +1,8 @@ error: value assigned to `x` is never read - --> $DIR/liveness-dead.rs:9:9 + --> $DIR/liveness-dead.rs:9:13 | LL | let mut x: isize = 3; - | ^^^^^ + | ^ | note: the lint level is defined here --> $DIR/liveness-dead.rs:2:9 @@ -20,10 +20,10 @@ LL | x = 4; = help: maybe it is overwritten before being read? error: value passed to `x` is never read - --> $DIR/liveness-dead.rs:20:7 + --> $DIR/liveness-dead.rs:20:11 | LL | fn f4(mut x: i32) { - | ^^^^^ + | ^ | = help: maybe it is overwritten before being read? diff --git a/src/test/ui/liveness/liveness-unused.stderr b/src/test/ui/liveness/liveness-unused.stderr index 2c5550ac47f22..4a6122681a946 100644 --- a/src/test/ui/liveness/liveness-unused.stderr +++ b/src/test/ui/liveness/liveness-unused.stderr @@ -44,10 +44,10 @@ LL | let x = 3; | ^ help: if this is intentional, prefix it with an underscore: `_x` error: variable `x` is assigned to, but never used - --> $DIR/liveness-unused.rs:30:9 + --> $DIR/liveness-unused.rs:30:13 | LL | let mut x = 3; - | ^^^^^ + | ^ | = note: consider using `_x` instead @@ -65,10 +65,10 @@ LL | #![deny(unused_assignments)] = help: maybe it is overwritten before being read? error: variable `z` is assigned to, but never used - --> $DIR/liveness-unused.rs:37:9 + --> $DIR/liveness-unused.rs:37:13 | LL | let mut z = 3; - | ^^^^^ + | ^ | = note: consider using `_z` instead