diff --git a/Cargo.lock b/Cargo.lock index 51332001d536e..928d19b1e2c3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4338,7 +4338,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.26" +version = "1.4.27" dependencies = [ "annotate-snippets 0.6.1", "anyhow", diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 1090d4a25c7cf..7d01f6a54995a 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -97,14 +97,12 @@ pub fn compile_codegen_unit( tcx: TyCtxt<'tcx>, cgu_name: Symbol, ) -> (ModuleCodegen, u64) { - let prof_timer = tcx.prof.generic_activity_with_arg("codegen_module", cgu_name.to_string()); let start_time = Instant::now(); let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx); let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result); let time_to_codegen = start_time.elapsed(); - drop(prof_timer); // We assume that the cost to run LLVM on a CGU is proportional to // the time we needed for codegenning it. @@ -112,6 +110,10 @@ pub fn compile_codegen_unit( fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); + let _prof_timer = tcx.prof.generic_activity_with_args( + "codegen_module", + &[cgu_name.to_string(), cgu.size_estimate().to_string()], + ); // Instantiate monomorphizations without filling out definitions yet... let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); { diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index e598d7a683d5a..5d13b7f27c704 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -272,6 +272,28 @@ impl SelfProfilerRef { }) } + #[inline(always)] + pub fn generic_activity_with_args( + &self, + event_label: &'static str, + event_args: &[String], + ) -> TimingGuard<'_> { + self.exec(EventFilter::GENERIC_ACTIVITIES, |profiler| { + let builder = EventIdBuilder::new(&profiler.profiler); + let event_label = profiler.get_or_alloc_cached_string(event_label); + let event_id = if profiler.event_filter_mask.contains(EventFilter::FUNCTION_ARGS) { + let event_args: Vec<_> = event_args + .iter() + .map(|s| profiler.get_or_alloc_cached_string(&s[..])) + .collect(); + builder.from_label_and_args(event_label, &event_args) + } else { + builder.from_label(event_label) + }; + TimingGuard::start(profiler, profiler.generic_activity_event_kind, event_id) + }) + } + /// Start profiling a query provider. Profiling continues until the /// TimingGuard returned from this call is dropped. #[inline(always)] diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 302713a21db9e..32104e6f00d44 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -200,6 +200,11 @@ pub trait Emitter { true } + /// Checks if we can use colors in the current output stream. + fn supports_color(&self) -> bool { + false + } + fn source_map(&self) -> Option<&Lrc>; /// Formats the substitutions of the primary_span @@ -504,6 +509,10 @@ impl Emitter for EmitterWriter { fn should_show_explain(&self) -> bool { !self.short_message } + + fn supports_color(&self) -> bool { + self.dst.supports_color() + } } /// An emitter that does nothing when emitting a diagnostic. @@ -2057,6 +2066,14 @@ impl Destination { Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)), } } + + fn supports_color(&self) -> bool { + match *self { + Self::Terminal(ref stream) => stream.supports_color(), + Self::Buffered(ref buffer) => buffer.buffer().supports_color(), + Self::Raw(_, supports_color) => supports_color, + } + } } impl<'a> WritableDst<'a> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a5237ffaf78fc..36cbd36a7705f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -422,6 +422,12 @@ pub struct TypeckResults<'tcx> { /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). pub generator_interior_types: Vec>, + + /// We sometimes treat byte string literals (which are of type `&[u8; N]`) + /// as `&[u8]`, depending on the pattern in which they are used. + /// This hashset records all instances where we behave + /// like this to allow `const_to_pat` to reliably handle this situation. + pub treat_byte_string_as_slice: ItemLocalSet, } impl<'tcx> TypeckResults<'tcx> { @@ -448,6 +454,7 @@ impl<'tcx> TypeckResults<'tcx> { closure_captures: Default::default(), closure_min_captures: Default::default(), generator_interior_types: Default::default(), + treat_byte_string_as_slice: Default::default(), } } @@ -683,6 +690,7 @@ impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { ref closure_captures, ref closure_min_captures, ref generator_interior_types, + ref treat_byte_string_as_slice, } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -717,6 +725,7 @@ impl<'a, 'tcx> HashStable> for TypeckResults<'tcx> { closure_captures.hash_stable(hcx, hasher); closure_min_captures.hash_stable(hcx, hasher); generator_interior_types.hash_stable(hcx, hasher); + treat_byte_string_as_slice.hash_stable(hcx, hasher); }) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 6370f8c375b2a..32fc0f008e972 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -18,6 +18,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts an evaluated constant to a pattern (if possible). /// This means aggregate values (like structs and enums) are converted /// to a pattern that matches the value (as if you'd compared via structural equality). + #[instrument(skip(self))] pub(super) fn const_to_pat( &self, cv: &'tcx ty::Const<'tcx>, @@ -25,15 +26,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span: Span, mir_structural_match_violation: bool, ) -> Pat<'tcx> { - debug!("const_to_pat: cv={:#?} id={:?}", cv, id); - debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); - let pat = self.tcx.infer_ctxt().enter(|infcx| { let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(cv, mir_structural_match_violation) }); - debug!("const_to_pat: pat={:?}", pat); + debug!(?pat); pat } } @@ -61,6 +59,8 @@ struct ConstToPat<'a, 'tcx> { infcx: InferCtxt<'a, 'tcx>, include_lint_checks: bool, + + treat_byte_string_as_slice: bool, } mod fallback_to_const_ref { @@ -88,6 +88,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { span: Span, infcx: InferCtxt<'a, 'tcx>, ) -> Self { + trace!(?pat_ctxt.typeck_results.hir_owner); ConstToPat { id, span, @@ -97,6 +98,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { saw_const_match_error: Cell::new(false), saw_const_match_lint: Cell::new(false), behind_reference: Cell::new(false), + treat_byte_string_as_slice: pat_ctxt + .typeck_results + .treat_byte_string_as_slice + .contains(&id.local_id), } } @@ -153,6 +158,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { cv: &'tcx ty::Const<'tcx>, mir_structural_match_violation: bool, ) -> Pat<'tcx> { + trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be // invoked except by this method. @@ -384,7 +390,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } PatKind::Wild } - // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this + // `&str` is represented as `ConstValue::Slice`, let's keep using this // optimization for now. ty::Str => PatKind::Constant { value: cv }, // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when @@ -393,11 +399,33 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // as slices. This means we turn `&[T; N]` constants into slice patterns, which // has no negative effects on pattern matching, even if we're actually matching on // arrays. - ty::Array(..) | + ty::Array(..) if !self.treat_byte_string_as_slice => { + let old = self.behind_reference.replace(true); + let array = tcx.deref_const(self.param_env.and(cv)); + let val = PatKind::Deref { + subpattern: Pat { + kind: Box::new(PatKind::Array { + prefix: tcx + .destructure_const(param_env.and(array)) + .fields + .iter() + .map(|val| self.recur(val, false)) + .collect::>()?, + slice: None, + suffix: vec![], + }), + span, + ty: pointee_ty, + }, + }; + self.behind_reference.set(old); + val + } + ty::Array(elem_ty, _) | // Cannot merge this with the catch all branch below, because the `const_deref` // changes the type from slice to array, we need to keep the original type in the // pattern. - ty::Slice(..) => { + ty::Slice(elem_ty) => { let old = self.behind_reference.replace(true); let array = tcx.deref_const(self.param_env.and(cv)); let val = PatKind::Deref { @@ -413,7 +441,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { suffix: vec![], }), span, - ty: pointee_ty, + ty: tcx.mk_slice(elem_ty), }, }; self.behind_reference.set(old); diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index dd8f4152c7c9e..a729912126e4f 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -149,6 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. + #[instrument(skip(self, ti))] fn check_pat( &self, pat: &'tcx Pat<'tcx>, @@ -156,8 +157,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { def_bm: BindingMode, ti: TopInfo<'tcx>, ) { - debug!("check_pat(pat={:?},expected={:?},def_bm={:?})", pat, expected, def_bm); - let path_res = match &pat.kind { PatKind::Path(qpath) => Some(self.resolve_ty_and_res_ufcs(qpath, pat.hir_id, pat.span)), _ => None, @@ -398,6 +397,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Ref(_, inner_ty, _) = expected.kind() { if matches!(inner_ty.kind(), ty::Slice(_)) { let tcx = self.tcx; + trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); + self.typeck_results + .borrow_mut() + .treat_byte_string_as_slice + .insert(lt.hir_id.local_id); pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index e54e00864831c..335f2cc2716c7 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -70,6 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.typeck_results.used_trait_imports = used_trait_imports; + wbcx.typeck_results.treat_byte_string_as_slice = + mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice); + wbcx.typeck_results.closure_captures = mem::take(&mut self.typeck_results.borrow_mut().closure_captures); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d6f8870c859f5..7a4ec77907080 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -193,7 +193,6 @@ crate fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let trait_items = cx.tcx.associated_items(did).in_definition_order().map(|item| item.clean(cx)).collect(); - let auto_trait = cx.tcx.trait_def(did).has_auto_impl; let predicates = cx.tcx.predicates_of(did); let generics = (cx.tcx.generics_of(did), predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); @@ -201,7 +200,6 @@ crate fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { - auto: auto_trait, unsafety: cx.tcx.trait_def(did).unsafety, generics, items: trait_items, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index daca4f8a9332f..95a0d335c4f91 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -883,14 +883,12 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx } } -impl<'a> Clean - for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId, Option) -{ - fn clean(&self, cx: &DocContext<'_>) -> Method { +impl<'a> Clean for (&'a hir::FnSig<'a>, &'a hir::Generics<'a>, hir::BodyId) { + fn clean(&self, cx: &DocContext<'_>) -> Function { let (generics, decl) = enter_impl_trait(cx, || (self.1.clean(cx), (&*self.0.decl, self.2).clean(cx))); let (all_types, ret_types) = get_all_types(&generics, &decl, cx); - Method { decl, generics, header: self.0.header, defaultness: self.3, all_types, ret_types } + Function { decl, generics, header: self.0.header, all_types, ret_types } } } @@ -1024,7 +1022,6 @@ impl Clean for doctree::Trait<'_> { stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), kind: TraitItem(Trait { - auto: self.is_auto.clean(cx), unsafety: self.unsafety, items: self.items.iter().map(|ti| ti.clean(cx)).collect(), generics: self.generics.clean(cx), @@ -1107,20 +1104,20 @@ impl Clean for hir::TraitItem<'_> { AssocConstItem(ty.clean(cx), default.map(|e| print_const_expr(cx, e))) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - let mut m = (sig, &self.generics, body, None).clean(cx); + let mut m = (sig, &self.generics, body).clean(cx); if m.header.constness == hir::Constness::Const && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } - MethodItem(m) + MethodItem(m, None) } hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => { let (generics, decl) = enter_impl_trait(cx, || { (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx)) }); let (all_types, ret_types) = get_all_types(&generics, &decl, cx); - let mut t = TyMethod { header: sig.header, decl, generics, all_types, ret_types }; + let mut t = Function { header: sig.header, decl, generics, all_types, ret_types }; if t.header.constness == hir::Constness::Const && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { @@ -1153,13 +1150,13 @@ impl Clean for hir::ImplItem<'_> { AssocConstItem(ty.clean(cx), Some(print_const_expr(cx, expr))) } hir::ImplItemKind::Fn(ref sig, body) => { - let mut m = (sig, &self.generics, body, Some(self.defaultness)).clean(cx); + let mut m = (sig, &self.generics, body).clean(cx); if m.header.constness == hir::Constness::Const && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } - MethodItem(m) + MethodItem(m, Some(self.defaultness)) } hir::ImplItemKind::TyAlias(ref ty) => { let type_ = ty.clean(cx); @@ -1235,21 +1232,23 @@ impl Clean for ty::AssocItem { ty::ImplContainer(_) => Some(self.defaultness), ty::TraitContainer(_) => None, }; - MethodItem(Method { - generics, - decl, - header: hir::FnHeader { - unsafety: sig.unsafety(), - abi: sig.abi(), - constness, - asyncness, + MethodItem( + Function { + generics, + decl, + header: hir::FnHeader { + unsafety: sig.unsafety(), + abi: sig.abi(), + constness, + asyncness, + }, + all_types, + ret_types, }, defaultness, - all_types, - ret_types, - }) + ) } else { - TyMethodItem(TyMethod { + TyMethodItem(Function { generics, decl, header: hir::FnHeader { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9dd8415341e98..a3677e3f5178f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -227,12 +227,8 @@ impl Item { crate fn is_default(&self) -> bool { match self.kind { - ItemKind::MethodItem(ref meth) => { - if let Some(defaultness) = meth.defaultness { - defaultness.has_value() && !defaultness.is_final() - } else { - false - } + ItemKind::MethodItem(_, Some(defaultness)) => { + defaultness.has_value() && !defaultness.is_final() } _ => false, } @@ -264,9 +260,9 @@ crate enum ItemKind { ImplItem(Impl), /// A method signature only. Used for required methods in traits (ie, /// non-default-methods). - TyMethodItem(TyMethod), + TyMethodItem(Function), /// A method with a body. - MethodItem(Method), + MethodItem(Function, Option), StructFieldItem(Type), VariantItem(Variant), /// `fn`s from an extern block @@ -910,25 +906,6 @@ crate struct Generics { crate where_predicates: Vec, } -#[derive(Clone, Debug)] -crate struct Method { - crate generics: Generics, - crate decl: FnDecl, - crate header: hir::FnHeader, - crate defaultness: Option, - crate all_types: Vec<(Type, TypeKind)>, - crate ret_types: Vec<(Type, TypeKind)>, -} - -#[derive(Clone, Debug)] -crate struct TyMethod { - crate header: hir::FnHeader, - crate decl: FnDecl, - crate generics: Generics, - crate all_types: Vec<(Type, TypeKind)>, - crate ret_types: Vec<(Type, TypeKind)>, -} - #[derive(Clone, Debug)] crate struct Function { crate decl: FnDecl, @@ -1026,7 +1003,6 @@ impl GetDefId for FnRetTy { #[derive(Clone, Debug)] crate struct Trait { - crate auto: bool, crate unsafety: hir::Unsafety, crate items: Vec, crate generics: Generics, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c79b2395d231b..9f35e57df418b 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,13 +1,13 @@ use rustc_ast as ast; use rustc_data_structures::sync::Lrc; -use rustc_errors::ErrorReported; +use rustc_errors::{ColorConfig, ErrorReported}; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_hir::{HirId, CRATE_HIR_ID}; use rustc_interface::interface; use rustc_middle::hir::map::Map; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, CrateType}; +use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::{lint, DiagnosticOutput, Session}; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; @@ -248,7 +248,8 @@ fn run_test( outdir: DirState, path: PathBuf, ) -> Result<(), TestFailure> { - let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts, edition); + let (test, line_offset, supports_color) = + make_test(test, Some(cratename), as_test_harness, opts, edition); let output_file = outdir.path().join("rust_out"); @@ -293,6 +294,20 @@ fn run_test( path.to_str().expect("target path must be valid unicode").to_string() } }); + if let ErrorOutputType::HumanReadable(kind) = options.error_format { + let (_, color_config) = kind.unzip(); + match color_config { + ColorConfig::Never => { + compiler.arg("--color").arg("never"); + } + ColorConfig::Always => { + compiler.arg("--color").arg("always"); + } + ColorConfig::Auto => { + compiler.arg("--color").arg(if supports_color { "always" } else { "never" }); + } + } + } compiler.arg("-"); compiler.stdin(Stdio::piped()); @@ -320,7 +335,10 @@ fn run_test( (true, false) => {} (false, true) => { if !error_codes.is_empty() { - error_codes.retain(|err| !out.contains(&format!("error[{}]: ", err))); + // We used to check if the output contained "error[{}]: " but since we added the + // colored output, we can't anymore because of the color escape characters before + // the ":". + error_codes.retain(|err| !out.contains(&format!("error[{}]", err))); if !error_codes.is_empty() { return Err(TestFailure::MissingErrorCodes(error_codes)); @@ -362,18 +380,19 @@ fn run_test( } /// Transforms a test into code that can be compiled into a Rust binary, and returns the number of -/// lines before the test code begins. +/// lines before the test code begins as well as if the output stream supports colors or not. crate fn make_test( s: &str, cratename: Option<&str>, dont_insert_main: bool, opts: &TestOptions, edition: Edition, -) -> (String, usize) { +) -> (String, usize, bool) { let (crate_attrs, everything_else, crates) = partition_source(s); let everything_else = everything_else.trim(); let mut line_offset = 0; let mut prog = String::new(); + let mut supports_color = false; if opts.attrs.is_empty() && !opts.display_warnings { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some @@ -399,7 +418,7 @@ crate fn make_test( // crate already is included. let result = rustc_driver::catch_fatal_errors(|| { rustc_span::with_session_globals(edition, || { - use rustc_errors::emitter::EmitterWriter; + use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::Handler; use rustc_parse::maybe_new_parser_from_source_str; use rustc_session::parse::ParseSess; @@ -411,8 +430,13 @@ crate fn make_test( // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + supports_color = + EmitterWriter::stderr(ColorConfig::Auto, None, false, false, Some(80), false) + .supports_color(); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); + // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, sm); @@ -482,7 +506,7 @@ crate fn make_test( Err(ErrorReported) => { // If the parser panicked due to a fatal error, pass the test code through unchanged. // The error will be reported during compilation. - return (s.to_owned(), 0); + return (s.to_owned(), 0, false); } }; @@ -532,7 +556,7 @@ crate fn make_test( debug!("final doctest:\n{}", prog); - (prog, line_offset) + (prog, line_offset, supports_color) } // FIXME(aburka): use a real parser to deal with multiline attributes diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a96186a95e16b..a024e9c72a43e 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -11,8 +11,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -26,8 +26,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -44,8 +44,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 3)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 3)); } #[test] @@ -61,8 +61,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -79,8 +79,8 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -98,8 +98,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -115,8 +115,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -134,8 +134,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 3)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 3)); // Adding more will also bump the returned line offset. opts.attrs.push("feature(hella_dope)".to_string()); @@ -147,8 +147,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 4)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 4)); } #[test] @@ -164,8 +164,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -180,8 +180,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } #[test] @@ -196,8 +196,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -210,8 +210,8 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let output = make_test(input, None, true, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } #[test] @@ -224,8 +224,8 @@ fn make_test_display_warnings() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } #[test] @@ -242,8 +242,8 @@ assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); let input = "extern crate hella_qwop; assert_eq!(asdf::foo, 4);"; @@ -256,8 +256,8 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 3)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 3)); } #[test] @@ -274,6 +274,6 @@ test_wrapper! { }" .to_string(); - let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 48518ef0dd8cf..1cbfbf50dd745 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -64,7 +64,6 @@ fn write_footer(out: &mut String, playground_button: Option<&str>) { /// How a span of text is classified. Mostly corresponds to token kinds. #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum Class { - None, Comment, DocComment, Attribute, @@ -89,7 +88,6 @@ impl Class { /// Returns the css class expected by rustdoc for each `Class`. fn as_html(self) -> &'static str { match self { - Class::None => "", Class::Comment => "comment", Class::DocComment => "doccomment", Class::Attribute => "attribute", @@ -112,7 +110,7 @@ impl Class { } enum Highlight<'a> { - Token { text: &'a str, class: Class }, + Token { text: &'a str, class: Option }, EnterSpan { class: Class }, ExitSpan, } @@ -166,8 +164,9 @@ impl<'a> Classifier<'a> { /// a couple of following ones as well. fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) { let lookahead = self.peek(); + let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None }); let class = match token { - TokenKind::Whitespace => Class::None, + TokenKind::Whitespace => return no_highlight(sink), TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => { if doc_style.is_some() { Class::DocComment @@ -192,12 +191,12 @@ impl<'a> Classifier<'a> { TokenKind::And => match lookahead { Some(TokenKind::And) => { let _and = self.tokens.next(); - sink(Highlight::Token { text: "&&", class: Class::Op }); + sink(Highlight::Token { text: "&&", class: Some(Class::Op) }); return; } Some(TokenKind::Eq) => { let _eq = self.tokens.next(); - sink(Highlight::Token { text: "&=", class: Class::Op }); + sink(Highlight::Token { text: "&=", class: Some(Class::Op) }); return; } Some(TokenKind::Whitespace) => Class::Op, @@ -228,7 +227,7 @@ impl<'a> Classifier<'a> { | TokenKind::At | TokenKind::Tilde | TokenKind::Colon - | TokenKind::Unknown => Class::None, + | TokenKind::Unknown => return no_highlight(sink), TokenKind::Question => Class::QuestionMark, @@ -237,7 +236,7 @@ impl<'a> Classifier<'a> { self.in_macro_nonterminal = true; Class::MacroNonTerminal } - _ => Class::None, + _ => return no_highlight(sink), }, // This might be the start of an attribute. We're going to want to @@ -253,8 +252,8 @@ impl<'a> Classifier<'a> { self.in_attribute = true; sink(Highlight::EnterSpan { class: Class::Attribute }); } - sink(Highlight::Token { text: "#", class: Class::None }); - sink(Highlight::Token { text: "!", class: Class::None }); + sink(Highlight::Token { text: "#", class: None }); + sink(Highlight::Token { text: "!", class: None }); return; } // Case 2: #[outer_attribute] @@ -264,16 +263,16 @@ impl<'a> Classifier<'a> { } _ => (), } - Class::None + return no_highlight(sink); } TokenKind::CloseBracket => { if self.in_attribute { self.in_attribute = false; - sink(Highlight::Token { text: "]", class: Class::None }); + sink(Highlight::Token { text: "]", class: None }); sink(Highlight::ExitSpan); return; } - Class::None + return no_highlight(sink); } TokenKind::Literal { kind, .. } => match kind { // Text literals. @@ -309,7 +308,7 @@ impl<'a> Classifier<'a> { }; // Anything that didn't return above is the simple case where we the // class just spans a single token, so we can use the `string` method. - sink(Highlight::Token { text, class }); + sink(Highlight::Token { text, class: Some(class) }); } fn peek(&mut self) -> Option { @@ -339,10 +338,10 @@ fn exit_span(out: &mut String) { /// ``` /// The latter can be thought of as a shorthand for the former, which is more /// flexible. -fn string(out: &mut String, text: T, klass: Class) { +fn string(out: &mut String, text: T, klass: Option) { match klass { - Class::None => write!(out, "{}", text).unwrap(), - klass => write!(out, "{}", klass.as_html(), text).unwrap(), + None => write!(out, "{}", text).unwrap(), + Some(klass) => write!(out, "{}", klass.as_html(), text).unwrap(), } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index cdb9aea5ad6ce..880c859dd1b23 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -243,7 +243,8 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .collect::>>() .join("\n"); let krate = krate.as_ref().map(|s| &**s); - let (test, _) = doctest::make_test(&test, krate, false, &Default::default(), edition); + let (test, _, _) = + doctest::make_test(&test, krate, false, &Default::default(), edition); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let edition_string = format!("&edition={}", edition); diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index cef9b8952dd7d..085ca01f58daa 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -167,7 +167,7 @@ crate fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { crate fn get_index_search_type(item: &clean::Item) -> Option { let (all_types, ret_types) = match item.kind { clean::FunctionItem(ref f) => (&f.all_types, &f.ret_types), - clean::MethodItem(ref m) => (&m.all_types, &m.ret_types), + clean::MethodItem(ref m, _) => (&m.all_types, &m.ret_types), clean::TyMethodItem(ref m) => (&m.all_types, &m.ret_types), _ => return None, }; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 78822e678d43e..28f7a4d316248 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2589,7 +2589,9 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, for (pos, m) in provided.iter().enumerate() { render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); match m.kind { - clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => { + clean::MethodItem(ref inner, _) + if !inner.generics.where_predicates.is_empty() => + { write!(w, ",\n {{ ... }}\n"); } _ => { @@ -2759,7 +2761,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, } write_loading_content(w, ""); - if t.auto { + if t.is_auto { write_small_section_header( w, "synthetic-implementors", @@ -2790,7 +2792,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, ); write_loading_content(w, ""); - if t.auto { + if t.is_auto { write_small_section_header( w, "synthetic-implementors", @@ -2968,7 +2970,9 @@ fn render_assoc_item( match item.kind { clean::StrippedItem(..) => {} clean::TyMethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent), - clean::MethodItem(ref m) => method(w, item, m.header, &m.generics, &m.decl, link, parent), + clean::MethodItem(ref m, _) => { + method(w, item, m.header, &m.generics, &m.decl, link, parent) + } clean::AssocConstItem(ref ty, ref default) => assoc_const( w, item, @@ -3545,7 +3549,7 @@ fn render_deref_methods( fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { let self_type_opt = match item.kind { - clean::MethodItem(ref method) => method.decl.self_type(), + clean::MethodItem(ref method, _) => method.decl.self_type(), clean::TyMethodItem(ref method) => method.decl.self_type(), _ => None, }; @@ -3752,8 +3756,7 @@ fn render_impl( (true, " hidden") }; match item.kind { - clean::MethodItem(clean::Method { .. }) - | clean::TyMethodItem(clean::TyMethod { .. }) => { + clean::MethodItem(..) | clean::TyMethodItem(_) => { // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{}.{}", item_type, name)); @@ -4454,7 +4457,7 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { sidebar.push_str(&sidebar_assoc_items(it)); sidebar.push_str("Implementors"); - if t.auto { + if t.is_auto { sidebar.push_str( "Auto Implementors", diff --git a/src/test/ui/const-generics/macro_rules-braces.full.stderr b/src/test/ui/const-generics/macro_rules-braces.full.stderr index f6e9aabd90774..e5b67f61a25b7 100644 --- a/src/test/ui/const-generics/macro_rules-braces.full.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.full.stderr @@ -9,6 +9,17 @@ help: enclose the `const` expression in braces LL | let _: baz!({ N }); | ^ ^ +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/macro_rules-braces.rs:54:17 + | +LL | let _: baz!(10 + 7); + | ^^^^^^ + | +help: enclose the `const` expression in braces + | +LL | let _: baz!({ 10 + 7 }); + | ^ ^ + error: constant expression depends on a generic parameter --> $DIR/macro_rules-braces.rs:10:13 | @@ -57,5 +68,5 @@ LL | let _: biz!({ N }); = note: this may fail depending on what value the parameter takes = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.min.stderr b/src/test/ui/const-generics/macro_rules-braces.min.stderr index 1fe18e3fc0231..a4ef732017dd5 100644 --- a/src/test/ui/const-generics/macro_rules-braces.min.stderr +++ b/src/test/ui/const-generics/macro_rules-braces.min.stderr @@ -9,6 +9,17 @@ help: enclose the `const` expression in braces LL | let _: baz!({ N }); | ^ ^ +error: expressions must be enclosed in braces to be used as const generic arguments + --> $DIR/macro_rules-braces.rs:54:17 + | +LL | let _: baz!(10 + 7); + | ^^^^^^ + | +help: enclose the `const` expression in braces + | +LL | let _: baz!({ 10 + 7 }); + | ^ ^ + error: generic parameters may not be used in const operations --> $DIR/macro_rules-braces.rs:31:20 | @@ -41,5 +52,5 @@ LL | let _: biz!({ N }); | = help: const parameters may only be used as standalone arguments, i.e. `N` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/const-generics/macro_rules-braces.rs b/src/test/ui/const-generics/macro_rules-braces.rs index c3e2c8ba20359..bc67d464f11bb 100644 --- a/src/test/ui/const-generics/macro_rules-braces.rs +++ b/src/test/ui/const-generics/macro_rules-braces.rs @@ -36,6 +36,26 @@ fn test() { let _: baz!({{ N }}); //[min]~ ERROR generic parameters may not let _: biz!(N); let _: biz!({ N }); //[min]~ ERROR generic parameters may not + let _: foo!(3); + let _: foo!({ 3 }); + let _: foo!({{ 3 }}); + let _: bar!(3); + let _: bar!({ 3 }); + let _: baz!(3); + let _: baz!({ 3 }); + let _: baz!({{ 3 }}); + let _: biz!(3); + let _: biz!({ 3 }); + let _: foo!(10 + 7); + let _: foo!({ 10 + 7 }); + let _: foo!({{ 10 + 7 }}); + let _: bar!(10 + 7); + let _: bar!({ 10 + 7 }); + let _: baz!(10 + 7); //~ ERROR expressions must be enclosed in braces + let _: baz!({ 10 + 7 }); + let _: baz!({{ 10 + 7 }}); + let _: biz!(10 + 7); + let _: biz!({ 10 + 7 }); } fn main() { diff --git a/src/test/ui/match/type_polymorphic_byte_str_literals.rs b/src/test/ui/match/type_polymorphic_byte_str_literals.rs new file mode 100644 index 0000000000000..cb44c1da76ba5 --- /dev/null +++ b/src/test/ui/match/type_polymorphic_byte_str_literals.rs @@ -0,0 +1,36 @@ +#[deny(unreachable_patterns)] + +fn parse_data1(data: &[u8]) -> u32 { + match data { + b"" => 1, + _ => 2, + } +} + +fn parse_data2(data: &[u8]) -> u32 { + match data { //~ ERROR non-exhaustive patterns: `&[_, ..]` not covered + b"" => 1, + } +} + +fn parse_data3(data: &[u8; 0]) -> u8 { + match data { + b"" => 1, + } +} + +fn parse_data4(data: &[u8]) -> u8 { + match data { //~ ERROR non-exhaustive patterns + b"aaa" => 0, + [_, _, _] => 1, + } +} + +fn parse_data5(data: &[u8; 3]) -> u8 { + match data { + b"aaa" => 0, + [_, _, _] => 1, + } +} + +fn main() {} diff --git a/src/test/ui/match/type_polymorphic_byte_str_literals.stderr b/src/test/ui/match/type_polymorphic_byte_str_literals.stderr new file mode 100644 index 0000000000000..6ce53a4f21ea2 --- /dev/null +++ b/src/test/ui/match/type_polymorphic_byte_str_literals.stderr @@ -0,0 +1,21 @@ +error[E0004]: non-exhaustive patterns: `&[_, ..]` not covered + --> $DIR/type_polymorphic_byte_str_literals.rs:11:11 + | +LL | match data { + | ^^^^ pattern `&[_, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[u8]` + +error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered + --> $DIR/type_polymorphic_byte_str_literals.rs:23:11 + | +LL | match data { + | ^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[u8]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr index 7968f9713ff22..ffc8433403fd5 100644 --- a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr @@ -7,11 +7,11 @@ LL | match buf { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[u8; 4]` -error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered +error[E0004]: non-exhaustive patterns: `&[]`, `&[_]`, `&[_, _]` and 2 more not covered --> $DIR/match-byte-array-patterns-2.rs:10:11 | LL | match buf { - | ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered + | ^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 2 more not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[u8]` diff --git a/src/tools/rustfmt b/src/tools/rustfmt index 293d7d01118c9..580d826e9b0f4 160000 --- a/src/tools/rustfmt +++ b/src/tools/rustfmt @@ -1 +1 @@ -Subproject commit 293d7d01118c9fb5479649399e1dae60322b8e09 +Subproject commit 580d826e9b0f407a2d4b36696cda2f0fa8d7ddaa