From fde8d11ca12e83fe2b07a536956f4a2725b24485 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Jun 2020 15:08:37 -0700 Subject: [PATCH 01/69] Don't pollute docs/suggestions with libstd deps Currently dependency crates of the standard library can sometimes leak into error messages such as when traits to import are suggested. Additionally they can leak into documentation such as in the list of "all traits implemented by `u32`". The dependencies of the standard library, however, are intended to be private. The dependencies of the standard library can't actually be stabl-y imported nor is the documentation that relevant since you can't import them on stable either. This commit updates both the compiler and rustdoc to ignore unstable traits in these two scenarios. Specifically the suggestion for traits to import ignore unstable traits, and similarly the list of traits implemented by a type excludes unstable traits. This commit is extracted from #73441 where the addition of some new dependencies to the standard library was showed to leak into various error messages and documentation. The intention here is to go ahead and land these changes ahead of that since it will likely take some time to land. --- src/librustc_typeck/check/method/suggest.rs | 6 ++++++ src/librustdoc/clean/inline.rs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 67bdd04d3715c..9c4873bccb299 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -937,6 +937,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // legal to implement. let mut candidates = all_traits(self.tcx) .into_iter() + // Don't issue suggestions for unstable traits since they're + // unlikely to be implementable anyway + .filter(|info| match self.tcx.lookup_stability(info.def_id) { + Some(attr) => attr.level.is_stable(), + None => true, + }) .filter(|info| { // We approximate the coherence rules to only suggest // traits that are legal to implement by requiring that diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 78628b198a3c3..ee1c17bad9f93 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -339,6 +339,16 @@ pub fn build_impl( return; } } + + // Skip foreign unstable traits from lists of trait implementations and + // such. This helps prevent dependencies of the standard library, for + // example, from getting documented as "traits `u32` implements" which + // isn't really too helpful. + if let Some(stab) = cx.tcx.lookup_stability(did) { + if stab.level.is_unstable() { + return; + } + } } let for_ = if let Some(did) = did.as_local() { From 99c15133638c42253592a9bbe705ff215c9dd563 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 27 Jun 2020 13:07:59 +0200 Subject: [PATCH 02/69] Small cleanup for E0705 explanation --- src/librustc_error_codes/error_codes/E0705.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0705.md b/src/librustc_error_codes/error_codes/E0705.md index 8fa09fe8e725b..1edd47de4cbbd 100644 --- a/src/librustc_error_codes/error_codes/E0705.md +++ b/src/librustc_error_codes/error_codes/E0705.md @@ -1,5 +1,5 @@ -A `#![feature]` attribute was declared for a feature that is stable in -the current edition, but not in all editions. +A `#![feature]` attribute was declared for a feature that is stable in the +current edition, but not in all editions. Erroneous code example: From 582071c1ebd5ec19ded8648223e9108b5ce65d85 Mon Sep 17 00:00:00 2001 From: joacar01 Date: Wed, 1 Jul 2020 16:02:09 +0100 Subject: [PATCH 03/69] Ignoring test case: [codegen] repr-transparent-aggregates-1.rs for aarch64 Copyright (c) 2020, Arm Limited. --- src/test/codegen/repr-transparent-aggregates-1.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index c23c57c8c5900..59f29e756fc9a 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -3,6 +3,7 @@ // min-system-llvm-version: 9.0 // ignore-arm +// ignore-aarch64 // ignore-mips // ignore-mips64 // ignore-powerpc From 69d5fc1a9f89c80dd9e16a43dff58f320b373630 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 28 Jun 2020 13:07:46 +0200 Subject: [PATCH 04/69] Clean up E0710 explanation --- src/librustc_error_codes/error_codes/E0710.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_error_codes/error_codes/E0710.md b/src/librustc_error_codes/error_codes/E0710.md index d9cefe2a6da72..b7037ea611ba2 100644 --- a/src/librustc_error_codes/error_codes/E0710.md +++ b/src/librustc_error_codes/error_codes/E0710.md @@ -1,4 +1,4 @@ -An unknown tool name found in scoped lint +An unknown tool name was found in a scoped lint. Erroneous code examples: From 9b6b400084fe617e2549d539963294a9ea178c46 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 2 Jul 2020 22:29:38 -0700 Subject: [PATCH 05/69] Remove some `ignore-stage1` annotations. --- src/test/compile-fail/asm-src-loc-codegen-units.rs | 2 -- src/test/run-make-fulldeps/issue-37839/Makefile | 2 -- src/test/run-make-fulldeps/issue-37893/Makefile | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/test/compile-fail/asm-src-loc-codegen-units.rs b/src/test/compile-fail/asm-src-loc-codegen-units.rs index c9415aed930d5..5b8690c3b98ce 100644 --- a/src/test/compile-fail/asm-src-loc-codegen-units.rs +++ b/src/test/compile-fail/asm-src-loc-codegen-units.rs @@ -1,5 +1,3 @@ -// WONTFIX(#20184) Needs landing pads (not present in stage1) or the compiler hangs. -// ignore-stage1 // compile-flags: -C codegen-units=2 // ignore-emscripten diff --git a/src/test/run-make-fulldeps/issue-37839/Makefile b/src/test/run-make-fulldeps/issue-37839/Makefile index c405d5c74d7af..f17ce537fb813 100644 --- a/src/test/run-make-fulldeps/issue-37839/Makefile +++ b/src/test/run-make-fulldeps/issue-37839/Makefile @@ -1,7 +1,5 @@ -include ../tools.mk -# ignore-stage1 - all: $(RUSTC) a.rs && $(RUSTC) b.rs $(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \ diff --git a/src/test/run-make-fulldeps/issue-37893/Makefile b/src/test/run-make-fulldeps/issue-37893/Makefile index df58d4f5d9486..27b69baf97787 100644 --- a/src/test/run-make-fulldeps/issue-37893/Makefile +++ b/src/test/run-make-fulldeps/issue-37893/Makefile @@ -1,6 +1,4 @@ -include ../tools.mk -# ignore-stage1 - all: $(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs From 95bf7b7dacca320d0965e3f9052ecbb9c4fc59bd Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Fri, 3 Jul 2020 11:22:33 -0400 Subject: [PATCH 06/69] add regression test for #61216 Fixes #61216. --- .../rustdoc-determinism/Makefile | 16 ++++++++++++++++ .../run-make-fulldeps/rustdoc-determinism/bar.rs | 1 + .../run-make-fulldeps/rustdoc-determinism/foo.rs | 1 + 3 files changed, 18 insertions(+) create mode 100644 src/test/run-make-fulldeps/rustdoc-determinism/Makefile create mode 100644 src/test/run-make-fulldeps/rustdoc-determinism/bar.rs create mode 100644 src/test/run-make-fulldeps/rustdoc-determinism/foo.rs diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/Makefile b/src/test/run-make-fulldeps/rustdoc-determinism/Makefile new file mode 100644 index 0000000000000..0534c2c383145 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/Makefile @@ -0,0 +1,16 @@ +-include ../tools.mk + +# Assert that the search index is generated deterministically, regardless of the +# order that crates are documented in. + +# ignore-windows +# Uses `diff`. + +all: + $(RUSTDOC) foo.rs -o $(TMPDIR)/foo_first + $(RUSTDOC) bar.rs -o $(TMPDIR)/foo_first + + $(RUSTDOC) bar.rs -o $(TMPDIR)/bar_first + $(RUSTDOC) foo.rs -o $(TMPDIR)/bar_first + + diff $(TMPDIR)/foo_first/search-index.js $(TMPDIR)/bar_first/search-index.js diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs b/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs new file mode 100644 index 0000000000000..ca05a6a9076c2 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs @@ -0,0 +1 @@ +pub struct Bar; diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs b/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs new file mode 100644 index 0000000000000..4a835673a596b --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs @@ -0,0 +1 @@ +pub struct Foo; From b0884c098bc3704f7ec9381ac1670eb923845127 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Jul 2020 14:48:31 +0200 Subject: [PATCH 07/69] Move #[doc(alias)] check in rustc --- src/librustc_passes/check_attr.rs | 30 +++++++++++++++++++ src/librustdoc/clean/types.rs | 28 ----------------- .../check-doc-alias-attr.rs | 1 + .../check-doc-alias-attr.stderr | 6 ++-- 4 files changed, 34 insertions(+), 31 deletions(-) rename src/test/{rustdoc-ui => ui}/check-doc-alias-attr.rs (88%) rename src/test/{rustdoc-ui => ui}/check-doc-alias-attr.stderr (92%) diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index ef84f251390e6..b44dc9e907960 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -70,6 +70,8 @@ impl CheckAttrVisitor<'tcx> { self.check_target_feature(attr, span, target) } else if attr.check_name(sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) + } else if attr.check_name(sym::doc) { + self.check_doc_alias(attr) } else { true }; @@ -216,6 +218,34 @@ impl CheckAttrVisitor<'tcx> { } } + fn check_doc_alias(&self, attr: &Attribute) -> bool { + if let Some(mi) = attr.meta() { + if let Some(list) = mi.meta_item_list() { + for meta in list { + if meta.check_name(sym::alias) { + if !meta.is_value_str() + || meta + .value_str() + .map(|s| s.to_string()) + .unwrap_or_else(String::new) + .is_empty() + { + self.tcx + .sess + .struct_span_err( + meta.span(), + "doc alias attribute expects a string: #[doc(alias = \"0\")]", + ) + .emit(); + return false; + } + } + } + } + } + true + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6dec016cc2ee3..5c76c840b1ddd 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -486,33 +486,6 @@ impl Attributes { }) } - /// Enforce the format of attributes inside `#[doc(...)]`. - pub fn check_doc_attributes( - diagnostic: &::rustc_errors::Handler, - mi: &ast::MetaItem, - ) -> Option<(String, String)> { - mi.meta_item_list().and_then(|list| { - for meta in list { - if meta.check_name(sym::alias) { - if !meta.is_value_str() - || meta - .value_str() - .map(|s| s.to_string()) - .unwrap_or_else(String::new) - .is_empty() - { - diagnostic.span_err( - meta.span(), - "doc alias attribute expects a string: #[doc(alias = \"0\")]", - ); - } - } - } - - None - }) - } - pub fn has_doc_flag(&self, flag: Symbol) -> bool { for attr in &self.other_attrs { if !attr.check_name(sym::doc) { @@ -556,7 +529,6 @@ impl Attributes { } else { if attr.check_name(sym::doc) { if let Some(mi) = attr.meta() { - Attributes::check_doc_attributes(&diagnostic, &mi); if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { // Extracted #[doc(cfg(...))] match Cfg::parse(cfg_mi) { diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs similarity index 88% rename from src/test/rustdoc-ui/check-doc-alias-attr.rs rename to src/test/ui/check-doc-alias-attr.rs index 2f01099107d9e..b02cc1a4545b1 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.rs +++ b/src/test/ui/check-doc-alias-attr.rs @@ -1,3 +1,4 @@ +#![crate_type = "lib"] #![feature(doc_alias)] #[doc(alias = "foo")] // ok! diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr similarity index 92% rename from src/test/rustdoc-ui/check-doc-alias-attr.stderr rename to src/test/ui/check-doc-alias-attr.stderr index 480acc821aaa8..268230ab44a0a 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -1,17 +1,17 @@ error: doc alias attribute expects a string: #[doc(alias = "0")] - --> $DIR/check-doc-alias-attr.rs:6:7 + --> $DIR/check-doc-alias-attr.rs:7:7 | LL | #[doc(alias)] | ^^^^^ error: doc alias attribute expects a string: #[doc(alias = "0")] - --> $DIR/check-doc-alias-attr.rs:7:7 + --> $DIR/check-doc-alias-attr.rs:8:7 | LL | #[doc(alias = 0)] | ^^^^^^^^^ error: doc alias attribute expects a string: #[doc(alias = "0")] - --> $DIR/check-doc-alias-attr.rs:8:7 + --> $DIR/check-doc-alias-attr.rs:9:7 | LL | #[doc(alias("bar"))] | ^^^^^^^^^^^^ From 24abe1646e24caca79cd649f71cd4806a488ee7d Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 8 Jul 2020 18:08:25 -0700 Subject: [PATCH 08/69] Disable 44056 test with debug on macos. --- src/test/codegen/issue-44056-macos-tls-align.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/codegen/issue-44056-macos-tls-align.rs b/src/test/codegen/issue-44056-macos-tls-align.rs index eee59be629bb6..5abbfa5dd24bb 100644 --- a/src/test/codegen/issue-44056-macos-tls-align.rs +++ b/src/test/codegen/issue-44056-macos-tls-align.rs @@ -1,6 +1,7 @@ // ignore-tidy-linelength // only-macos // no-system-llvm +// ignore-debug: the debug assertions get in the way // compile-flags: -O #![crate_type = "rlib"] From 1acccb0f52bc5812ae9431b36b6f8f232a513d1f Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Wed, 1 Jul 2020 23:48:48 -0400 Subject: [PATCH 09/69] Make hir ProjectionKind more precise This commit also categorizing access as Field, Index, or Subslice. Ideas are taken from `mir::ProjectionElem`. Proposed changes: https://github.com/rust-lang/project-rfc-2229/blob/master/hir-place-target.md Closes: https://github.com/rust-lang/project-rfc-2229/issues/1, https://github.com/rust-lang/project-rfc-2229/issues/2 Co-authored-by: Aman Arora Co-authored-by: Chris Pardy Co-authored-by: Dhruv Jauhar --- src/librustc_typeck/expr_use_visitor.rs | 3 + src/librustc_typeck/mem_categorization.rs | 170 ++++++++++++++++++++-- 2 files changed, 159 insertions(+), 14 deletions(-) diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 4e5ef4329c2c6..1be32729b1ee5 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -11,8 +11,10 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::PatKind; +use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, adjustment, TyCtxt}; +use rustc_target::abi::VariantIdx; use crate::mem_categorization as mc; use rustc_span::Span; @@ -396,6 +398,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { &*with_expr, with_place.clone(), with_field.ty(self.tcx(), substs), + mc::ProjectionKind::Field(f_index as u32, VariantIdx::new(0)), ); self.delegate_consume(&field_place); } diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index ac42ce80689ec..70fe2c2cda512 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -54,11 +54,14 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; +use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::PatKind; +use rustc_index::vec::Idx; use rustc_infer::infer::InferCtxt; use rustc_span::Span; +use rustc_target::abi::VariantIdx; use rustc_trait_selection::infer::InferCtxtExt; #[derive(Clone, Debug)] @@ -77,8 +80,20 @@ pub enum PlaceBase { pub enum ProjectionKind { /// A dereference of a pointer, reference or `Box` of the given type Deref, - /// An index or a field - Other, + + /// `B.F` where `B` is the base expression and `F` is + /// the field. The field is identified by which variant + /// it appears in along with a field index. The variant + /// is used for enums. + Field(u32, VariantIdx), + + /// Some index like `B[x]`, where `B` is the base + /// expression. We don't preserve the index `x` because + /// we won't need it. + Index, + + /// A subslice covering a range of values like `B[x..y]`. + Subslice, } #[derive(Clone, Debug)] @@ -406,7 +421,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { hir::ExprKind::Field(ref base, _) => { let base = self.cat_expr(&base)?; debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base); - Ok(self.cat_projection(expr, base, expr_ty)) + + let field_idx = self + .tables + .field_indices() + .get(expr.hir_id) + .cloned() + .expect("Field index not found"); + + Ok(self.cat_projection( + expr, + base, + expr_ty, + ProjectionKind::Field(field_idx as u32, VariantIdx::new(0)), + )) } hir::ExprKind::Index(ref base, _) => { @@ -419,7 +447,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_overloaded_place(expr, base) } else { let base = self.cat_expr(&base)?; - Ok(self.cat_projection(expr, base, expr_ty)) + Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index)) } } @@ -533,9 +561,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { node: &N, base_place: PlaceWithHirId<'tcx>, ty: Ty<'tcx>, + kind: ProjectionKind, ) -> PlaceWithHirId<'tcx> { let mut projections = base_place.place.projections; - projections.push(Projection { kind: ProjectionKind::Other, ty: ty }); + projections.push(Projection { kind: kind, ty: ty }); let ret = PlaceWithHirId::new( node.hir_id(), base_place.place.base_ty, @@ -609,6 +638,75 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { self.cat_pattern_(place, pat, &mut op) } + /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn variant_index_for_adt( + &self, + qpath: &hir::QPath<'_>, + pat_hir_id: hir::HirId, + span: Span, + ) -> McResult { + let res = self.tables.qpath_res(qpath, pat_hir_id); + let ty = self.tables.node_type(pat_hir_id); + let adt_def = match ty.kind { + ty::Adt(adt_def, _) => adt_def, + _ => { + self.tcx() + .sess + .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + return Err(()); + } + }; + + match res { + Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)), + Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { + Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id)) + } + Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) + | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::SelfCtor(..) + | Res::SelfTy(..) => { + // Structs and Unions have only have one variant. + Ok(VariantIdx::new(0)) + } + _ => bug!("expected ADT path, found={:?}", res), + } + } + + /// Returns the total number of fields in an ADT variant used within a pattern. + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn total_fields_in_adt_variant( + &self, + pat_hir_id: hir::HirId, + variant_index: VariantIdx, + span: Span, + ) -> McResult { + let ty = self.tables.node_type(pat_hir_id); + match ty.kind { + ty::Adt(adt_def, _) => Ok(adt_def.variants[variant_index].fields.len()), + _ => { + self.tcx() + .sess + .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + return Err(()); + } + } + } + + /// Returns the total number of fields in a tuple used within a Tuple pattern. + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult { + let ty = self.tables.node_type(pat_hir_id); + match ty.kind { + ty::Tuple(substs) => Ok(substs.len()), + _ => { + self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); + return Err(()); + } + } + } + // FIXME(#19596) This is a workaround, but there should be a better way to do this fn cat_pattern_( &self, @@ -679,20 +777,54 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { op(&place_with_id, pat); match pat.kind { - PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => { - // S(p1, ..., pN) or (p1, ..., pN) - for subpat in subpats.iter() { + PatKind::Tuple(ref subpats, dots_pos) => { + // (p1, ..., pN) + let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?; + + for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { let subpat_ty = self.pat_ty_adjusted(&subpat)?; - let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty); + let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0)); + let sub_place = + self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); self.cat_pattern_(sub_place, &subpat, op)?; } } - PatKind::Struct(_, field_pats, _) => { + PatKind::TupleStruct(ref qpath, ref subpats, dots_pos) => { + // S(p1, ..., pN) + let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; + let total_fields = + self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?; + + for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { + let subpat_ty = self.pat_ty_adjusted(&subpat)?; + let projection_kind = ProjectionKind::Field(i as u32, variant_index); + let sub_place = + self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); + self.cat_pattern_(sub_place, &subpat, op)?; + } + } + + PatKind::Struct(ref qpath, field_pats, _) => { // S { f1: p1, ..., fN: pN } + + let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; + for fp in field_pats { let field_ty = self.pat_ty_adjusted(&fp.pat)?; - let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty); + let field_index = self + .tables + .field_indices() + .get(fp.hir_id) + .cloned() + .expect("no index for a field"); + + let field_place = self.cat_projection( + pat, + place_with_id.clone(), + field_ty, + ProjectionKind::Field(field_index as u32, variant_index), + ); self.cat_pattern_(field_place, &fp.pat, op)?; } } @@ -723,13 +855,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { return Err(()); } }; - let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty); + let elt_place = self.cat_projection( + pat, + place_with_id.clone(), + element_ty, + ProjectionKind::Index, + ); for before_pat in before { self.cat_pattern_(elt_place.clone(), &before_pat, op)?; } if let Some(ref slice_pat) = *slice { let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?; - let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty); + let slice_place = self.cat_projection( + pat, + place_with_id, + slice_pat_ty, + ProjectionKind::Subslice, + ); self.cat_pattern_(slice_place, &slice_pat, op)?; } for after_pat in after { From 9f91a9540d5058eb7b384d1a58e81a4672fea7b4 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 9 Jul 2020 10:20:52 -0700 Subject: [PATCH 10/69] Ignore changes when debug assertions are enabled. --- src/test/codegen/issue-44056-macos-tls-align.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/codegen/issue-44056-macos-tls-align.rs b/src/test/codegen/issue-44056-macos-tls-align.rs index 5abbfa5dd24bb..2270eca501428 100644 --- a/src/test/codegen/issue-44056-macos-tls-align.rs +++ b/src/test/codegen/issue-44056-macos-tls-align.rs @@ -1,18 +1,18 @@ // ignore-tidy-linelength // only-macos // no-system-llvm -// ignore-debug: the debug assertions get in the way // compile-flags: -O #![crate_type = "rlib"] #![feature(thread_local)] -// CHECK: @STATIC_VAR_1 = thread_local local_unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4 +// local_unnamed_addr does not appear when std is built with debug assertions. +// CHECK: @STATIC_VAR_1 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4 #[no_mangle] #[thread_local] static mut STATIC_VAR_1: [u32; 8] = [0; 8]; -// CHECK: @STATIC_VAR_2 = thread_local local_unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4 +// CHECK: @STATIC_VAR_2 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4 #[no_mangle] #[thread_local] static mut STATIC_VAR_2: [u32; 8] = [4; 8]; From 382d5bb715859423a086c6b26e651c18adf0dcb9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 14 Jul 2020 15:45:01 +0200 Subject: [PATCH 11/69] Focus on the current file in the source file sidebar --- src/librustdoc/html/static/source-script.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index cfbfe6675f52b..5c39e760f44d4 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -140,4 +140,9 @@ function createSourceSidebar() { }); main.insertBefore(sidebar, main.firstChild); + // Focus on the current file in the source files sidebar. + var selected_elems = Array.prototype.slice.call(sidebar.getElementsByClassName("selected")); + if (selected_elems.length > 0) { + selected_elems[0].focus(); + } } From c3ee75d956a52791dd0e50391f941030a112f7ef Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 27 Jun 2020 13:55:15 -0400 Subject: [PATCH 12/69] rustdoc: glue tokens before highlighting Fixes #72684. This commit also modifies the signature of `Classifier::new` to avoid copying the source being highlighted. --- src/librustdoc/html/highlight.rs | 51 +++++++++++----- src/librustdoc/html/highlight/tests.rs | 82 ++++++++++++++++++++++++++ src/librustdoc/html/markdown.rs | 4 +- src/librustdoc/html/render.rs | 7 ++- src/librustdoc/html/sources.rs | 11 ++-- 5 files changed, 133 insertions(+), 22 deletions(-) create mode 100644 src/librustdoc/html/highlight/tests.rs diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index c4bc73770a76b..d4302d0cb546b 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -12,15 +12,17 @@ use std::io; use std::io::prelude::*; use rustc_ast::token::{self, Token}; +use rustc_data_structures::sync::Lrc; use rustc_parse::lexer; use rustc_session::parse::ParseSess; +use rustc_span::hygiene::SyntaxContext; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym}; -use rustc_span::{FileName, Span}; +use rustc_span::{BytePos, FileName, SourceFile, Span}; /// Highlights `src`, returning the HTML output. pub fn render_with_highlighting( - src: &str, + src: String, class: Option<&str>, playground_button: Option<&str>, tooltip: Option<(&str, &str)>, @@ -38,12 +40,13 @@ pub fn render_with_highlighting( } let sess = ParseSess::with_silent_emitter(); - let sf = sess + let source_file = sess .source_map() - .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned()); + .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src); + + let classifier_source_file = Lrc::clone(&source_file); let highlight_result = rustc_driver::catch_fatal_errors(|| { - let lexer = lexer::StringReader::new(&sess, sf, None); - let mut classifier = Classifier::new(lexer, sess.source_map()); + let mut classifier = Classifier::new(&sess, classifier_source_file); let mut highlighted_source = vec![]; if classifier.write_source(&mut highlighted_source).is_err() { @@ -61,9 +64,17 @@ pub fn render_with_highlighting( write_footer(&mut out, playground_button).unwrap(); } Err(()) => { + // Get the source back out of the source map to avoid a copy in the happy path. + let span = + Span::new(BytePos(0), BytePos(source_file.byte_length()), SyntaxContext::root()); + let src = sess + .source_map() + .span_to_snippet(span) + .expect("could not retrieve snippet from artificial source file"); + // If errors are encountered while trying to highlight, just emit // the unhighlighted source. - write!(out, "
{}
", Escape(src)).unwrap(); + write!(out, "
{}
", Escape(&src)).unwrap(); } } @@ -73,10 +84,10 @@ pub fn render_with_highlighting( /// Processes a program (nested in the internal `lexer`), classifying strings of /// text by highlighting category (`Class`). Calls out to a `Writer` to write /// each span of text in sequence. -struct Classifier<'a> { - lexer: lexer::StringReader<'a>, +struct Classifier<'sess> { + lexer: lexer::StringReader<'sess>, peek_token: Option, - source_map: &'a SourceMap, + source_map: &'sess SourceMap, // State of the classifier. in_attribute: bool, @@ -154,6 +165,7 @@ impl Writer for U { } } +#[derive(Debug)] enum HighlightError { LexError, IoError(io::Error), @@ -165,12 +177,14 @@ impl From for HighlightError { } } -impl<'a> Classifier<'a> { - fn new(lexer: lexer::StringReader<'a>, source_map: &'a SourceMap) -> Classifier<'a> { +impl<'sess> Classifier<'sess> { + fn new(sess: &ParseSess, source_file: Lrc) -> Classifier<'_> { + let lexer = lexer::StringReader::new(sess, source_file, None); + Classifier { lexer, peek_token: None, - source_map, + source_map: sess.source_map(), in_attribute: false, in_macro: false, in_macro_nonterminal: false, @@ -209,11 +223,17 @@ impl<'a> Classifier<'a> { /// source. fn write_source(&mut self, out: &mut W) -> Result<(), HighlightError> { loop { - let next = self.try_next_token()?; + let mut next = self.try_next_token()?; if next == token::Eof { break; } + // Glue any tokens that need to be glued. + if let Some(joint) = next.glue(self.peek()?) { + next = joint; + let _ = self.try_next_token()?; + } + self.write_token(out, next)?; } @@ -429,3 +449,6 @@ fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> { fn write_footer(out: &mut dyn Write, playground_button: Option<&str>) -> io::Result<()> { write!(out, "{}\n", if let Some(button) = playground_button { button } else { "" }) } + +#[cfg(test)] +mod tests; diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs new file mode 100644 index 0000000000000..01b25fd6be4ac --- /dev/null +++ b/src/librustdoc/html/highlight/tests.rs @@ -0,0 +1,82 @@ +use rustc_ast::attr::with_session_globals; +use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; +use rustc_span::FileName; + +use super::Classifier; + +fn highlight(src: &str) -> String { + let mut out = vec![]; + + with_session_globals(Edition::Edition2018, || { + let sess = ParseSess::with_silent_emitter(); + let source_file = sess.source_map().new_source_file( + FileName::Custom(String::from("rustdoc-highlighting")), + src.to_owned(), + ); + + let mut classifier = Classifier::new(&sess, source_file); + classifier.write_source(&mut out).unwrap(); + }); + + String::from_utf8(out).unwrap() +} + +#[test] +fn function() { + assert_eq!( + highlight("fn main() {}"), + r#"fn main() {}"#, + ); +} + +#[test] +fn statement() { + assert_eq!( + highlight("let foo = true;"), + concat!( + r#"let foo "#, + r#"= true;"#, + ), + ); +} + +#[test] +fn inner_attr() { + assert_eq!( + highlight(r##"#![crate_type = "lib"]"##), + concat!( + r##"#![crate_type "##, + r##"= "lib"]"##, + ), + ); +} + +#[test] +fn outer_attr() { + assert_eq!( + highlight(r##"#[cfg(target_os = "linux")]"##), + concat!( + r##"#[cfg("##, + r##"target_os = "##, + r##""linux")]"##, + ), + ); +} + +#[test] +fn mac() { + assert_eq!( + highlight("mac!(foo bar)"), + concat!( + r#"mac!("#, + r#"foo bar)"#, + ), + ); +} + +// Regression test for #72684 +#[test] +fn andand() { + assert_eq!(highlight("&&"), r#"&&"#); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a0f8eb04e2efb..d09fe454e137d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -292,7 +292,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { if let Some((s1, s2)) = tooltip { s.push_str(&highlight::render_with_highlighting( - &text, + text, Some(&format!( "rust-example-rendered{}", if ignore != Ignore::None { @@ -313,7 +313,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { Some(Event::Html(s.into())) } else { s.push_str(&highlight::render_with_highlighting( - &text, + text, Some(&format!( "rust-example-rendered{}", if ignore != Ignore::None { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8fa581180ef60..7d05caa3aea84 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -4525,7 +4525,12 @@ fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) { fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) { wrap_into_docblock(w, |w| { - w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), None, None)) + w.write_str(&highlight::render_with_highlighting( + t.source.clone(), + Some("macro"), + None, + None, + )) }); document(w, cx, it) } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 03f79b931868b..e3215921f125c 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -75,7 +75,7 @@ impl<'a> SourceCollector<'a> { return Ok(()); } - let contents = match fs::read_to_string(&p) { + let mut contents = match fs::read_to_string(&p) { Ok(contents) => contents, Err(e) => { return Err(Error::new(e, &p)); @@ -83,8 +83,9 @@ impl<'a> SourceCollector<'a> { }; // Remove the utf-8 BOM if any - let contents = - if contents.starts_with("\u{feff}") { &contents[3..] } else { &contents[..] }; + if contents.starts_with("\u{feff}") { + contents.drain(..3); + } // Create the intermediate directories let mut cur = self.dst.clone(); @@ -122,7 +123,7 @@ impl<'a> SourceCollector<'a> { &self.scx.layout, &page, "", - |buf: &mut _| print_src(buf, &contents), + |buf: &mut _| print_src(buf, contents), &self.scx.style_files, ); self.scx.fs.write(&cur, v.as_bytes())?; @@ -160,7 +161,7 @@ where /// Wrapper struct to render the source code of a file. This will do things like /// adding line numbers to the left-hand side. -fn print_src(buf: &mut Buffer, s: &str) { +fn print_src(buf: &mut Buffer, s: String) { let lines = s.lines().count(); let mut cols = 0; let mut tmp = lines; From 0f4e4a022c0aab65e40a4b60ea7984075891826d Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 15 Jul 2020 10:55:40 +0000 Subject: [PATCH 13/69] rustdoc: Rename internal API fns to `into_string` to avoid surprising listed in API guidelines. --- src/librustdoc/externalfiles.rs | 4 ++-- src/librustdoc/html/markdown.rs | 10 +++++----- src/librustdoc/html/markdown/tests.rs | 7 ++++--- src/librustdoc/html/render.rs | 10 +++++----- src/librustdoc/markdown.rs | 4 ++-- src/tools/error_index_generator/main.rs | 2 +- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 8b5a3a2ba6131..c8121d39d0f8f 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -37,14 +37,14 @@ impl ExternalHtml { let bc = format!( "{}{}", bc, - Markdown(&m_bc, &[], id_map, codes, edition, playground).to_string() + Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string() ); let ac = load_external_files(after_content, diag)?; let m_ac = load_external_files(md_after_content, diag)?; let ac = format!( "{}{}", ac, - Markdown(&m_ac, &[], id_map, codes, edition, playground).to_string() + Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string() ); Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac }) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a0f8eb04e2efb..8847f2bca36e9 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -13,7 +13,7 @@ //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); //! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None); -//! let html = md.to_string(); +//! let html = md.into_string(); //! // ... something using html //! ``` @@ -848,7 +848,7 @@ impl LangString { } impl Markdown<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let Markdown(md, links, mut ids, codes, edition, playground) = self; // This is actually common enough to special-case @@ -878,7 +878,7 @@ impl Markdown<'_> { } impl MarkdownWithToc<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let MarkdownWithToc(md, mut ids, codes, edition, playground) = self; let p = Parser::new_ext(md, opts()); @@ -899,7 +899,7 @@ impl MarkdownWithToc<'_> { } impl MarkdownHtml<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let MarkdownHtml(md, mut ids, codes, edition, playground) = self; // This is actually common enough to special-case @@ -926,7 +926,7 @@ impl MarkdownHtml<'_> { } impl MarkdownSummaryLine<'_> { - pub fn to_string(self) -> String { + pub fn into_string(self) -> String { let MarkdownSummaryLine(md, links) = self; // This is actually common enough to special-case if md.is_empty() { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index bf0451a1d9d65..783977d285dc4 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -134,7 +134,7 @@ fn test_header() { fn t(input: &str, expect: &str) { let mut map = IdMap::new(); let output = - Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string(); + Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); assert_eq!(output, expect, "original: {}", input); } @@ -166,7 +166,8 @@ fn test_header() { fn test_header_ids_multiple_blocks() { let mut map = IdMap::new(); fn t(map: &mut IdMap, input: &str, expect: &str) { - let output = Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string(); + let output = + Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); assert_eq!(output, expect, "original: {}", input); } @@ -228,7 +229,7 @@ fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); let output = - MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string(); + MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string(); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8fa581180ef60..efeece536ffb4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1894,7 +1894,7 @@ fn render_markdown( cx.shared.edition, &cx.shared.playground ) - .to_string() + .into_string() ) } @@ -2184,7 +2184,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: ", name = *myitem.name.as_ref().unwrap(), stab_tags = stability_tags(myitem), - docs = MarkdownSummaryLine(doc_value, &myitem.links()).to_string(), + docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), class = myitem.type_(), add = add, stab = stab.unwrap_or_else(String::new), @@ -2277,7 +2277,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { cx.shared.edition, &cx.shared.playground, ); - message.push_str(&format!(": {}", html.to_string())); + message.push_str(&format!(": {}", html.into_string())); } stability.push(format!( "
👎 {}
", @@ -2331,7 +2331,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { cx.shared.edition, &cx.shared.playground, ) - .to_string() + .into_string() ); } @@ -3631,7 +3631,7 @@ fn render_impl( cx.shared.edition, &cx.shared.playground ) - .to_string() + .into_string() ); } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index e0753bcd70f29..89d184e35cb06 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -68,9 +68,9 @@ pub fn render>( let mut ids = IdMap::new(); let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); let text = if !options.markdown_no_toc { - MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).to_string() + MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string() } else { - Markdown(text, &[], &mut ids, error_codes, edition, &playground).to_string() + Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string() }; let err = write!( diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 9aea859999cea..c4292d041d051 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -127,7 +127,7 @@ impl Formatter for HTMLFormatter { DEFAULT_EDITION, &Some(playground) ) - .to_string() + .into_string() )? } None => write!(output, "

No description.

\n")?, From a5275ff41521bb8e5a70f49f8ed420eaac7ed7de Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 20 Jun 2020 15:57:23 -0400 Subject: [PATCH 14/69] Don't run everybody_loops for rustdoc Instead, ignore resolution errors that occur in item bodies. The reason this can't ignore item bodies altogether is because `const fn` could be used in generic types, for example `[T; f()]` --- src/librustc_interface/passes.rs | 29 +++++++++++----------- src/librustc_resolve/late.rs | 42 +++++++++++++++++++++++--------- src/librustc_resolve/lib.rs | 4 +-- src/test/rustdoc/doc-cfg.rs | 4 ++- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 241ba869d3eb1..1862b47b9adb3 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -354,24 +354,13 @@ fn configure_and_expand_inner<'a>( ) }); - // If we're actually rustdoc then there's no need to actually compile - // anything, so switch everything to just looping - let mut should_loop = sess.opts.actually_rustdoc; - if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty { - should_loop |= true; - } - if should_loop { - log::debug!("replacing bodies with loop {{}}"); - util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate); - } + let crate_types = sess.crate_types(); + let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); let has_proc_macro_decls = sess.time("AST_validation", || { rustc_ast_passes::ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer()) }); - let crate_types = sess.crate_types(); - let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); - // For backwards compatibility, we don't try to run proc macro injection // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being // specified. This should only affect users who manually invoke 'rustdoc', as @@ -417,7 +406,19 @@ fn configure_and_expand_inner<'a>( println!("{}", json::as_json(&krate)); } - resolver.resolve_crate(&krate); + // If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items. + // anything, so switch everything to just looping + resolver.resolve_crate(&krate, sess.opts.actually_rustdoc); + + //let mut should_loop = sess.opts.actually_rustdoc; + let mut should_loop = false; + if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty { + should_loop |= true; + } + if should_loop { + log::debug!("replacing bodies with loop {{}}"); + util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate); + } // Needs to go *after* expansion to be able to check the results of macro expansion. sess.time("complete_gated_feature_checking", || { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index c165a601408fd..ddce82494e1ba 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -394,6 +394,11 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// Fields used to add information to diagnostic errors. diagnostic_metadata: DiagnosticMetadata<'ast>, + + /// Whether to report resolution errors for item bodies. + /// + /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items. + ignore_bodies: bool, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. @@ -627,7 +632,10 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { - fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> { + fn new( + resolver: &'b mut Resolver<'a>, + ignore_bodies: bool, + ) -> LateResolutionVisitor<'a, 'b, 'ast> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; @@ -644,6 +652,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { label_ribs: Vec::new(), current_trait_ref: None, diagnostic_metadata: DiagnosticMetadata::default(), + ignore_bodies, } } @@ -757,7 +766,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { return if self.is_label_valid_from_rib(i) { Some(*id) } else { - self.r.report_error( + self.report_error( original_span, ResolutionError::UnreachableLabel { name: label.name, @@ -775,7 +784,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label)); } - self.r.report_error( + self.report_error( original_span, ResolutionError::UndeclaredLabel { name: label.name, suggestion }, ); @@ -1008,7 +1017,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if seen_bindings.contains_key(&ident) { let span = seen_bindings.get(&ident).unwrap(); let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span); - self.r.report_error(param.ident.span, err); + self.report_error(param.ident.span, err); } seen_bindings.entry(ident).or_insert(param.ident.span); @@ -1274,7 +1283,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .is_err() { let path = &self.current_trait_ref.as_ref().unwrap().1.path; - self.r.report_error(span, err(ident.name, &path_names_to_string(path))); + self.report_error(span, err(ident.name, &path_names_to_string(path))); } } } @@ -1390,7 +1399,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if inconsistent_vars.contains_key(name) { v.could_be_path = false; } - self.r.report_error( + self.report_error( *v.origin.iter().next().unwrap(), ResolutionError::VariableNotBoundInPattern(v), ); @@ -1400,7 +1409,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let mut inconsistent_vars = inconsistent_vars.iter().collect::>(); inconsistent_vars.sort(); for (name, v) in inconsistent_vars { - self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); + self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1)); } // 5) Finally bubble up all the binding maps. @@ -1550,7 +1559,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // `Variant(a, a)`: _ => IdentifierBoundMoreThanOnceInSamePattern, }; - self.r.report_error(ident.span, error(ident.name)); + self.report_error(ident.span, error(ident.name)); } // Record as bound if it's valid: @@ -1624,7 +1633,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // to something unusable as a pattern (e.g., constructor function), // but we still conservatively report an error, see // issues/33118#issuecomment-233962221 for one reason why. - self.r.report_error( + self.report_error( ident.span, ResolutionError::BindingShadowsSomethingUnacceptable( pat_src.descr(), @@ -1809,7 +1818,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { Err(err) => { if let Some(err) = report_errors_for_call(self, err) { - self.r.report_error(err.span, err.node); + self.report_error(err.span, err.node); } PartialRes::new(Res::Err) @@ -1843,6 +1852,15 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false } } + /// A wrapper around [`Resolver::report_error`]. + /// + /// This doesn't emit errors for function bodies if `ignore_bodies` is set. + fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) { + if !self.ignore_bodies || self.diagnostic_metadata.current_function.is_none() { + self.r.report_error(span, resolution_error); + } + } + // Resolve in alternative namespaces if resolution in the primary namespace fails. fn resolve_qpath_anywhere( &mut self, @@ -2339,8 +2357,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } impl<'a> Resolver<'a> { - pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { - let mut late_resolution_visitor = LateResolutionVisitor::new(self); + pub(crate) fn late_resolve_crate(&mut self, krate: &Crate, ignore_bodies: bool) { + let mut late_resolution_visitor = LateResolutionVisitor::new(self, ignore_bodies); visit::walk_crate(&mut late_resolution_visitor, krate); for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() { self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label"); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a265c15c18bc9..786dc28ba0eec 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1441,13 +1441,13 @@ impl<'a> Resolver<'a> { } /// Entry point to crate resolution. - pub fn resolve_crate(&mut self, krate: &Crate) { + pub fn resolve_crate(&mut self, krate: &Crate, ignore_bodies: bool) { let _prof_timer = self.session.prof.generic_activity("resolve_crate"); ImportResolver { r: self }.finalize_imports(); self.finalize_macro_resolutions(); - self.late_resolve_crate(krate); + self.late_resolve_crate(krate, ignore_bodies); self.check_unused(krate); self.report_errors(krate); diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index aa407b7e92618..8664930bc94f4 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -57,5 +57,7 @@ pub unsafe fn uses_target_feature() { // 'This is supported with target feature avx only.' #[doc(cfg(target_feature = "avx"))] pub fn uses_cfg_target_feature() { - uses_target_feature(); + unsafe { + uses_target_feature(); + } } From b3187aabd20637e0bb9a930b4b930a079b785ca9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 20 Jun 2020 16:41:39 -0400 Subject: [PATCH 15/69] Don't run analysis pass in rustdoc - Explicitly check for missing docs - Don't run any lints except those we explicitly specified --- src/librustc_interface/passes.rs | 1 - src/librustdoc/core.rs | 12 +++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 1862b47b9adb3..b814283555b83 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -410,7 +410,6 @@ fn configure_and_expand_inner<'a>( // anything, so switch everything to just looping resolver.resolve_crate(&krate, sess.opts.actually_rustdoc); - //let mut should_loop = sess.opts.actually_rustdoc; let mut should_loop = false; if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty { should_loop |= true; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a222920c7d292..061d2d21ec927 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -372,7 +372,10 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt crate_name, lint_caps, register_lints: None, - override_queries: None, + override_queries: Some(|_sess, local_providers, external_providers| { + local_providers.lint_mod = |_, _| {}; + external_providers.lint_mod = |_, _| {}; + }), registry: rustc_driver::diagnostics_registry(), }; @@ -416,10 +419,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); global_ctxt.enter(|tcx| { - tcx.analysis(LOCAL_CRATE).ok(); - - // Abort if there were any errors so far - sess.abort_if_errors(); + sess.time("missing_docs", || { + rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); + }); 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 From 1b8accb7497e6fe66be331e40f8663d198a6b648 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 20 Jun 2020 17:01:03 -0400 Subject: [PATCH 16/69] Add an option not to report resolution errors for rustdoc - Remove unnecessary `should_loop` variable - Report errors for trait implementations These should give resolution errors because they are visible outside the current scope. Without these errors, rustdoc will give ICEs: ``` thread 'rustc' panicked at 'attempted .def_id() on invalid res: Err', /home/joshua/src/rust/src/libstd/macros.rs:16:9 15: rustc_hir::def::Res::def_id at /home/joshua/src/rust/src/librustc_hir/def.rs:382 16: rustdoc::clean::utils::register_res at src/librustdoc/clean/utils.rs:627 17: rustdoc::clean::utils::resolve_type at src/librustdoc/clean/utils.rs:587 ``` - Add much more extensive tests + fn -> impl -> fn + fn -> impl -> fn -> macro + errors in function parameters + errors in trait bounds + errors in the type implementing the trait + unknown bounds for the type + unknown types in function bodies + errors generated by macros - Use explicit state instead of trying to reconstruct it from random info - Use an enum instead of a boolean - Add example of ignored error --- src/librustc_interface/passes.rs | 25 +++--- src/librustc_resolve/late.rs | 99 +++++++++++++++++----- src/librustc_resolve/lib.rs | 3 +- src/test/rustdoc-ui/impl-fn-nesting.rs | 49 +++++++++++ src/test/rustdoc-ui/impl-fn-nesting.stderr | 60 +++++++++++++ src/test/rustdoc/doc-cfg.rs | 4 +- 6 files changed, 201 insertions(+), 39 deletions(-) create mode 100644 src/test/rustdoc-ui/impl-fn-nesting.rs create mode 100644 src/test/rustdoc-ui/impl-fn-nesting.stderr diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index b814283555b83..690ed9decb9ef 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -233,6 +233,8 @@ fn configure_and_expand_inner<'a>( resolver_arenas: &'a ResolverArenas<'a>, metadata_loader: &'a MetadataLoaderDyn, ) -> Result<(ast::Crate, Resolver<'a>)> { + use rustc_resolve::IgnoreState; + log::trace!("configure_and_expand_inner"); pre_expansion_lint(sess, lint_store, &krate); @@ -354,13 +356,18 @@ fn configure_and_expand_inner<'a>( ) }); - let crate_types = sess.crate_types(); - let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); + if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty { + log::debug!("replacing bodies with loop {{}}"); + util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate); + } let has_proc_macro_decls = sess.time("AST_validation", || { rustc_ast_passes::ast_validation::check_crate(sess, &krate, &mut resolver.lint_buffer()) }); + let crate_types = sess.crate_types(); + let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); + // For backwards compatibility, we don't try to run proc macro injection // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being // specified. This should only affect users who manually invoke 'rustdoc', as @@ -407,17 +414,9 @@ fn configure_and_expand_inner<'a>( } // If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items. - // anything, so switch everything to just looping - resolver.resolve_crate(&krate, sess.opts.actually_rustdoc); - - let mut should_loop = false; - if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty { - should_loop |= true; - } - if should_loop { - log::debug!("replacing bodies with loop {{}}"); - util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate); - } + let ignore_bodies = + if sess.opts.actually_rustdoc { IgnoreState::Ignore } else { IgnoreState::Report }; + resolver.resolve_crate(&krate, ignore_bodies); // Needs to go *after* expansion to be able to check the results of macro expansion. sess.time("complete_gated_feature_checking", || { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index ddce82494e1ba..637326bb88d86 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -376,6 +376,19 @@ struct DiagnosticMetadata<'ast> { current_let_binding: Option<(Span, Option, Option)>, } +/// Keeps track of whether errors should be reported. +/// +/// Used by rustdoc to ignore errors in function bodies. +/// This is just a fancy boolean so it can have doc-comments. +#[derive(Copy, Clone, Debug)] +pub enum IgnoreState { + /// We are at global scope or in a trait implementation, so all errors should be reported. + Report, + /// We are in a function body, so errors shouldn't be reported. + Ignore, + // Note that we don't need to worry about macros, which must always be resolved (or we wouldn't have gotten to the late pass). +} + struct LateResolutionVisitor<'a, 'b, 'ast> { r: &'b mut Resolver<'a>, @@ -395,10 +408,12 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// Fields used to add information to diagnostic errors. diagnostic_metadata: DiagnosticMetadata<'ast>, - /// Whether to report resolution errors for item bodies. + /// State used to know whether to ignore resolution errors for item bodies. /// /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items. - ignore_bodies: bool, + /// In most cases this will be `None`, in which case errors will always be reported. + /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body. + ignore_bodies: Option, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. @@ -502,6 +517,10 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_fn_ret_ty(this, &declaration.output); + let previous_ignore = this.ignore_bodies.take(); + // Ignore errors in function bodies if originally passed `ignore_state: true` + // Be sure not to set this until the function signature has been resolved. + this.ignore_bodies = previous_ignore.and(Some(IgnoreState::Ignore)); // Resolve the function body, potentially inside the body of an async closure match fn_kind { FnKind::Fn(.., body) => walk_list!(this, visit_block, body), @@ -509,6 +528,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }; debug!("(resolving function) leaving function"); + this.ignore_bodies = previous_ignore; }) }); self.diagnostic_metadata.current_function = previous_value; @@ -634,7 +654,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn new( resolver: &'b mut Resolver<'a>, - ignore_bodies: bool, + ignore_bodies: IgnoreState, ) -> LateResolutionVisitor<'a, 'b, 'ast> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. @@ -652,7 +672,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { label_ribs: Vec::new(), current_trait_ref: None, diagnostic_metadata: DiagnosticMetadata::default(), - ignore_bodies, + ignore_bodies: match ignore_bodies { + // errors at module scope should always be reported + IgnoreState::Ignore => Some(IgnoreState::Report), + IgnoreState::Report => None, + }, } } @@ -842,7 +866,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }; let report_error = |this: &Self, ns| { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what)); + if this.should_report_errs() { + this.r + .session + .span_err(ident.span, &format!("imports cannot refer to {}", what)); + } }; for &ns in nss { @@ -1166,6 +1194,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_items: &'ast [P], ) { debug!("resolve_implementation"); + let old_ignore = self.ignore_bodies.take(); + // Never ignore errors in trait implementations. + self.ignore_bodies = old_ignore.and(Some(IgnoreState::Report)); // If applicable, create a rib for the type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { // Dummy self type for better errors if `Self` is used in the trait path. @@ -1261,6 +1292,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); }); }); + self.ignore_bodies = old_ignore; } fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) @@ -1298,6 +1330,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn resolve_local(&mut self, local: &'ast Local) { + debug!("resolving local ({:?})", local); // Resolve the type. walk_list!(self, visit_ty, &local.ty); @@ -1686,18 +1719,27 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source: PathSource<'ast>, crate_lint: CrateLint, ) -> PartialRes { + log::debug!("smart_resolve_path_fragment(id={:?},qself={:?},path={:?}", id, qself, path); let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); let report_errors = |this: &mut Self, res: Option| { - let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); - - let def_id = this.parent_scope.module.normal_ancestor_id; - let instead = res.is_some(); - let suggestion = - if res.is_none() { this.report_missing_type_error(path) } else { None }; - - this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion }); + if this.should_report_errs() { + let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res); + + let def_id = this.parent_scope.module.normal_ancestor_id; + let instead = res.is_some(); + let suggestion = + if res.is_none() { this.report_missing_type_error(path) } else { None }; + + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead, + suggestion, + }); + } PartialRes::new(Res::Err) }; @@ -1755,13 +1797,17 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let def_id = this.parent_scope.module.normal_ancestor_id; - this.r.use_injections.push(UseError { - err, - candidates, - def_id, - instead: false, - suggestion: None, - }); + if this.should_report_errs() { + this.r.use_injections.push(UseError { + err, + candidates, + def_id, + instead: false, + suggestion: None, + }); + } else { + err.cancel(); + } // We don't return `Some(parent_err)` here, because the error will // be already printed as part of the `use` injections @@ -1856,11 +1902,20 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { /// /// This doesn't emit errors for function bodies if `ignore_bodies` is set. fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) { - if !self.ignore_bodies || self.diagnostic_metadata.current_function.is_none() { + if self.should_report_errs() { self.r.report_error(span, resolution_error); } } + #[inline] + fn should_report_errs(&self) -> bool { + debug!("should_report_errs(state={:?})", self.ignore_bodies); + match self.ignore_bodies { + None | Some(IgnoreState::Report) => true, + Some(IgnoreState::Ignore) => false, + } + } + // Resolve in alternative namespaces if resolution in the primary namespace fails. fn resolve_qpath_anywhere( &mut self, @@ -2357,7 +2412,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } impl<'a> Resolver<'a> { - pub(crate) fn late_resolve_crate(&mut self, krate: &Crate, ignore_bodies: bool) { + pub(crate) fn late_resolve_crate(&mut self, krate: &Crate, ignore_bodies: IgnoreState) { let mut late_resolution_visitor = LateResolutionVisitor::new(self, ignore_bodies); visit::walk_crate(&mut late_resolution_visitor, krate); for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 786dc28ba0eec..23bd0028bd1dd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -15,6 +15,7 @@ #![feature(or_patterns)] #![recursion_limit = "256"] +pub use late::IgnoreState; pub use rustc_hir::def::{Namespace, PerNS}; use Determinacy::*; @@ -1441,7 +1442,7 @@ impl<'a> Resolver<'a> { } /// Entry point to crate resolution. - pub fn resolve_crate(&mut self, krate: &Crate, ignore_bodies: bool) { + pub fn resolve_crate(&mut self, krate: &Crate, ignore_bodies: IgnoreState) { let _prof_timer = self.session.prof.generic_activity("resolve_crate"); ImportResolver { r: self }.finalize_imports(); diff --git a/src/test/rustdoc-ui/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs new file mode 100644 index 0000000000000..d2dd8d835fd79 --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.rs @@ -0,0 +1,49 @@ +// Ensure that rustdoc gives errors for trait impls inside function bodies that don't resolve. +// See https://github.com/rust-lang/rust/pull/73566 +pub struct ValidType; +pub trait ValidTrait {} +pub trait NeedsBody { + type Item; + fn f(); +} + +/// This function has docs +pub fn f(a: UnknownType, b: B) { +//~^ ERROR cannot find trait `UnknownBound` in this scope +//~| ERROR cannot find type `UnknownType` in this scope + impl UnknownTrait for ValidType {} //~ ERROR cannot find trait `UnknownTrait` + impl UnknownTrait for T {} + //~^ ERROR cannot find trait `UnknownBound` in this scope + //~| ERROR cannot find trait `UnknownTrait` in this scope + impl ValidTrait for UnknownType {} + //~^ ERROR cannot find type `UnknownType` in this scope + impl ValidTrait for ValidType where ValidTrait: UnknownBound {} + //~^ ERROR cannot find trait `UnknownBound` in this scope + + /// This impl has documentation + impl NeedsBody for ValidType { + type Item = UnknownType; + //~^ ERROR cannot find type `UnknownType` in this scope + + /// This function has documentation + fn f() { + ::a(); + content::shouldnt::matter(); + unknown_macro!(); + //~^ ERROR cannot find macro `unknown_macro` in this scope + + /// This is documentation for a macro + macro_rules! can_define_macros_here_too { + () => { + this::content::should::also::be::ignored() + } + } + can_define_macros_here_too!(); + + /// This also is documented. + pub fn doubly_nested(c: UnknownTypeShouldBeIgnored) { + + } + } + } +} diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr new file mode 100644 index 0000000000000..f8629964c0701 --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.stderr @@ -0,0 +1,60 @@ +error: cannot find macro `unknown_macro` in this scope + --> $DIR/impl-fn-nesting.rs:32:13 + | +LL | unknown_macro!(); + | ^^^^^^^^^^^^^ + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:11:13 + | +LL | pub fn f(a: UnknownType, b: B) { + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:11:30 + | +LL | pub fn f(a: UnknownType, b: B) { + | ^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownTrait` in this scope + --> $DIR/impl-fn-nesting.rs:14:10 + | +LL | impl UnknownTrait for ValidType {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownTrait` in this scope + --> $DIR/impl-fn-nesting.rs:15:27 + | +LL | impl UnknownTrait for T {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:15:13 + | +LL | impl UnknownTrait for T {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:18:25 + | +LL | impl ValidTrait for UnknownType {} + | ^^^^^^^^^^^ not found in this scope + +error[E0405]: cannot find trait `UnknownBound` in this scope + --> $DIR/impl-fn-nesting.rs:20:53 + | +LL | impl ValidTrait for ValidType where ValidTrait: UnknownBound {} + | ^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:25:21 + | +LL | type Item = UnknownType; + | ^^^^^^^^^^^ not found in this scope + +error: Compilation failed, aborting rustdoc + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0405, E0412. +For more information about an error, try `rustc --explain E0405`. diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index 8664930bc94f4..aa407b7e92618 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -57,7 +57,5 @@ pub unsafe fn uses_target_feature() { // 'This is supported with target feature avx only.' #[doc(cfg(target_feature = "avx"))] pub fn uses_cfg_target_feature() { - unsafe { - uses_target_feature(); - } + uses_target_feature(); } From 14a8707cde48c7914af307f4687056d829ad2de9 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 7 Jun 2020 15:13:40 -0700 Subject: [PATCH 17/69] Add `rustdoc` tests from #72088 --- src/test/rustdoc/macro-in-async-block.rs | 9 +++++++++ src/test/rustdoc/macro-in-closure.rs | 7 +++++++ 2 files changed, 16 insertions(+) create mode 100644 src/test/rustdoc/macro-in-async-block.rs diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs new file mode 100644 index 0000000000000..b4aaacf7b3d40 --- /dev/null +++ b/src/test/rustdoc/macro-in-async-block.rs @@ -0,0 +1,9 @@ +// Regression issue for rustdoc ICE encountered in PR #72088. +// edition:2018 +#![feature(decl_macro)] + +fn main() { + async { + macro m() {} + }; +} diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs index 298ff601de89f..b4411d927e271 100644 --- a/src/test/rustdoc/macro-in-closure.rs +++ b/src/test/rustdoc/macro-in-closure.rs @@ -6,4 +6,11 @@ fn main() { || { macro m() {} }; + + let _ = || { + macro n() {} + }; + + let cond = true; + let _ = || if cond { macro n() {} } else { panic!() }; } From 768d6a4950d66f1a0e1e7793a984fb638494d1c5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 3 Jul 2020 18:41:23 -0400 Subject: [PATCH 18/69] Don't ICE on errors in function returning impl trait Instead, report the error. This emits the errors on-demand, without special-casing `impl Trait`, so it should catch all ICEs of this kind, including ones that haven't been found yet. Since the error is emitted during type-checking there is less info about the error; see comments in the code for details. - Add test case for -> impl Trait - Add test for impl trait with alias - Move EmitIgnoredResolutionErrors to rustdoc This makes `fn typeck_item_bodies` public, which is not desired behavior. That change should be removed once https://github.com/rust-lang/rust/pull/74070 is merged. - Don't visit nested closures twice --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/core.rs | 78 +++++++++++++++++++ src/librustdoc/lib.rs | 1 + src/test/rustdoc-ui/error-in-impl-trait.rs | 28 +++++++ .../rustdoc-ui/error-in-impl-trait.stderr | 39 ++++++++++ src/test/rustdoc/impl-trait-alias.rs | 14 ++++ 7 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 src/test/rustdoc-ui/error-in-impl-trait.rs create mode 100644 src/test/rustdoc-ui/error-in-impl-trait.stderr create mode 100644 src/test/rustdoc/impl-trait-alias.rs diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index bc01da324b66f..514600b4733d4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -955,7 +955,7 @@ where val.fold_with(&mut FixupFolder { tcx }) } -fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> { +pub fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> { let fallback = move || tcx.type_of(def_id.to_def_id()); typeck_tables_of_with_fallback(tcx, def_id, fallback) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9ba2545ba63cb..79e1585ce3cdb 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -78,7 +78,7 @@ extern crate rustc_middle; pub mod expr_use_visitor; mod astconv; -mod check; +pub mod check; mod check_unused; mod coherence; mod collect; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 061d2d21ec927..3d0da0e9157f7 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -375,6 +375,15 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt override_queries: Some(|_sess, local_providers, external_providers| { local_providers.lint_mod = |_, _| {}; external_providers.lint_mod = |_, _| {}; + //let old_typeck = local_providers.typeck_tables_of; + local_providers.typeck_tables_of = move |tcx, def_id| { + let hir = tcx.hir(); + let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); + debug!("visiting body for {:?}", def_id); + EmitIgnoredResolutionErrors::new(&tcx.sess).visit_body(body); + rustc_typeck::check::typeck_tables_of(tcx, def_id) + //DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) + }; }), registry: rustc_driver::diagnostics_registry(), }; @@ -572,6 +581,75 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }) } +use rustc_hir::def::Res; +use rustc_hir::{ + intravisit::{NestedVisitorMap, Visitor}, + Path, +}; +use rustc_middle::hir::map::Map; + +/* +thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx>, rustc_span::def_id::LocalDefId) -> &'tcx rustc_middle::ty::TypeckTables<'tcx> = { + let mut providers = rustc_middle::ty::query::Providers::default(); + rustc_typeck::provide(&mut providers); + providers.typeck_tables_of +}); +*/ + +/// Due to https://github.com/rust-lang/rust/pull/73566, +/// the name resolution pass may find errors that are never emitted. +/// If typeck is called after this happens, then we'll get an ICE: +/// 'Res::Error found but not reported'. To avoid this, emit the errors now. +struct EmitIgnoredResolutionErrors<'a> { + session: &'a Session, +} + +impl<'a> EmitIgnoredResolutionErrors<'a> { + fn new(session: &'a Session) -> Self { + Self { session } + } +} + +impl<'a> Visitor<'a> for EmitIgnoredResolutionErrors<'_> { + type Map = Map<'a>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + // If we visit nested bodies, then we will report errors twice for e.g. nested closures + NestedVisitorMap::None + } + + fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) { + log::debug!("visiting path {:?}", path); + if path.res == Res::Err { + // We have less context here than in rustc_resolve, + // so we can only emit the name and span. + // However we can give a hint that rustc_resolve will have more info. + // NOTE: this is a very rare case (only 4 out of several hundred thousand crates in a crater run) + // NOTE: so it's ok for it to be slow + let label = format!( + "could not resolve path `{}`", + path.segments + .iter() + .map(|segment| segment.ident.as_str().to_string()) + .collect::>() + .join("::") + ); + let mut err = rustc_errors::struct_span_err!( + self.session, + path.span, + E0433, + "failed to resolve: {}", + label + ); + err.span_label(path.span, label); + err.note("this error was originally ignored because you are running `rustdoc`"); + err.note("try running again with `rustc` and you may get a more detailed error"); + err.emit(); + } + // NOTE: this does _not_ visit the path segments + } +} + /// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter /// for `impl Trait` in argument position. #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 57151e2b20002..4bd6b1260ccef 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -94,6 +94,7 @@ pub fn main() { 32_000_000 // 32MB on other platforms }; rustc_driver::set_sigpipe_handler(); + rustc_driver::install_ice_hook(); env_logger::init_from_env("RUSTDOC_LOG"); let res = std::thread::Builder::new() .stack_size(thread_stack_size) diff --git a/src/test/rustdoc-ui/error-in-impl-trait.rs b/src/test/rustdoc-ui/error-in-impl-trait.rs new file mode 100644 index 0000000000000..fbe663a61890f --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait.rs @@ -0,0 +1,28 @@ +// edition:2018 +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait +pub fn g() -> impl ValidTrait { + error::_in::impl_trait() + //~^ ERROR failed to resolve +} + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + error::_in::impl_trait::alias(); + //~^ ERROR failed to resolve + (|| error::_in::impl_trait::alias::nested::closure())() + //~^ ERROR failed to resolve +} + +/// This used to work with ResolveBodyWithLoop. +/// However now that we ignore type checking instead of modifying the function body, +/// the return type is seen as `impl Future`, not a `u32`. +/// So it no longer allows errors in the function body. +pub async fn a() -> u32 { + error::_in::async_fn() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait.stderr b/src/test/rustdoc-ui/error-in-impl-trait.stderr new file mode 100644 index 0000000000000..4df40da9b7cea --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait.stderr @@ -0,0 +1,39 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait` + --> $DIR/error-in-impl-trait.rs:9:5 + | +LL | error::_in::impl_trait() + | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias` + --> $DIR/error-in-impl-trait.rs:15:5 + | +LL | error::_in::impl_trait::alias(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` + --> $DIR/error-in-impl-trait.rs:17:9 + | +LL | (|| error::_in::impl_trait::alias::nested::closure())() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn` + --> $DIR/error-in-impl-trait.rs:26:5 + | +LL | error::_in::async_fn() + | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc/impl-trait-alias.rs b/src/test/rustdoc/impl-trait-alias.rs new file mode 100644 index 0000000000000..54c3f856ddb3c --- /dev/null +++ b/src/test/rustdoc/impl-trait-alias.rs @@ -0,0 +1,14 @@ +#![feature(type_alias_impl_trait)] + +trait MyTrait {} +impl MyTrait for i32 {} + +// @has impl_trait_alias/type.Foo.html 'Foo' +/// debug type +pub type Foo = impl MyTrait; + +// @has impl_trait_alias/fn.foo.html 'foo' +/// debug function +pub fn foo() -> Foo { + 1 +} From a93bcc9a7b8e48865d3df59fc936a0553e4d1e37 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 9 Jul 2020 09:13:59 -0400 Subject: [PATCH 19/69] Recurse into function bodies, but don't typeck closures Previously, rustdoc would issue a delay_span_bug ICE on the following code: ```rust pub fn a() -> impl Fn() -> u32 { || content::doesnt::matter() } ``` This wasn't picked up earlier because having `type Alias = impl Trait;` in the same module caused _all closures_ to be typechecked, even if they wouldn't normally. Additionally, if _any_ error was emitted, no delay_span_bug would be emitted. So as part of this commit all of the tests were separated out into different files. --- src/librustdoc/core.rs | 28 ++++++++----- src/test/rustdoc-ui/error-in-impl-trait.rs | 28 ------------- .../rustdoc-ui/error-in-impl-trait.stderr | 39 ------------------- .../rustdoc-ui/error-in-impl-trait/README.md | 7 ++++ .../rustdoc-ui/error-in-impl-trait/async.rs | 10 +++++ .../error-in-impl-trait/async.stderr | 12 ++++++ .../rustdoc-ui/error-in-impl-trait/closure.rs | 5 +++ .../error-in-impl-trait/closure.stderr | 12 ++++++ .../impl-keyword-closure.rs | 6 +++ .../impl-keyword-closure.stderr | 12 ++++++ .../error-in-impl-trait/impl-keyword.rs | 6 +++ .../error-in-impl-trait/impl-keyword.stderr | 12 ++++++ .../trait-alias-closure.rs | 10 +++++ .../trait-alias-closure.stderr | 12 ++++++ .../error-in-impl-trait/trait-alias.rs | 10 +++++ .../error-in-impl-trait/trait-alias.stderr | 12 ++++++ 16 files changed, 145 insertions(+), 76 deletions(-) delete mode 100644 src/test/rustdoc-ui/error-in-impl-trait.rs delete mode 100644 src/test/rustdoc-ui/error-in-impl-trait.stderr create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/README.md create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/async.rs create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/async.stderr create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/closure.rs create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/closure.stderr create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3d0da0e9157f7..413faff283e19 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -377,10 +377,18 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt external_providers.lint_mod = |_, _| {}; //let old_typeck = local_providers.typeck_tables_of; local_providers.typeck_tables_of = move |tcx, def_id| { + // Closures' tables come from their outermost function, + // as they are part of the same "inference environment". + // This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`) + let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); + if outer_def_id != def_id { + return tcx.typeck_tables_of(outer_def_id); + } + let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); debug!("visiting body for {:?}", def_id); - EmitIgnoredResolutionErrors::new(&tcx.sess).visit_body(body); + EmitIgnoredResolutionErrors::new(&tcx.sess, hir).visit_body(body); rustc_typeck::check::typeck_tables_of(tcx, def_id) //DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) }; @@ -600,22 +608,24 @@ thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx> /// the name resolution pass may find errors that are never emitted. /// If typeck is called after this happens, then we'll get an ICE: /// 'Res::Error found but not reported'. To avoid this, emit the errors now. -struct EmitIgnoredResolutionErrors<'a> { +struct EmitIgnoredResolutionErrors<'a, 'hir> { session: &'a Session, + hir_map: Map<'hir>, } -impl<'a> EmitIgnoredResolutionErrors<'a> { - fn new(session: &'a Session) -> Self { - Self { session } +impl<'a, 'hir> EmitIgnoredResolutionErrors<'a, 'hir> { + fn new(session: &'a Session, hir_map: Map<'hir>) -> Self { + Self { session, hir_map } } } -impl<'a> Visitor<'a> for EmitIgnoredResolutionErrors<'_> { - type Map = Map<'a>; +impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { + type Map = Map<'hir>; fn nested_visit_map(&mut self) -> NestedVisitorMap { - // If we visit nested bodies, then we will report errors twice for e.g. nested closures - NestedVisitorMap::None + // We need to recurse into nested closures, + // since those will fallback to the parent for type checking. + NestedVisitorMap::OnlyBodies(self.hir_map) } fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) { diff --git a/src/test/rustdoc-ui/error-in-impl-trait.rs b/src/test/rustdoc-ui/error-in-impl-trait.rs deleted file mode 100644 index fbe663a61890f..0000000000000 --- a/src/test/rustdoc-ui/error-in-impl-trait.rs +++ /dev/null @@ -1,28 +0,0 @@ -// edition:2018 -#![feature(type_alias_impl_trait)] - -pub trait ValidTrait {} -type ImplTrait = impl ValidTrait; - -/// This returns impl trait -pub fn g() -> impl ValidTrait { - error::_in::impl_trait() - //~^ ERROR failed to resolve -} - -/// This returns impl trait, but using a type alias -pub fn h() -> ImplTrait { - error::_in::impl_trait::alias(); - //~^ ERROR failed to resolve - (|| error::_in::impl_trait::alias::nested::closure())() - //~^ ERROR failed to resolve -} - -/// This used to work with ResolveBodyWithLoop. -/// However now that we ignore type checking instead of modifying the function body, -/// the return type is seen as `impl Future`, not a `u32`. -/// So it no longer allows errors in the function body. -pub async fn a() -> u32 { - error::_in::async_fn() - //~^ ERROR failed to resolve -} diff --git a/src/test/rustdoc-ui/error-in-impl-trait.stderr b/src/test/rustdoc-ui/error-in-impl-trait.stderr deleted file mode 100644 index 4df40da9b7cea..0000000000000 --- a/src/test/rustdoc-ui/error-in-impl-trait.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait` - --> $DIR/error-in-impl-trait.rs:9:5 - | -LL | error::_in::impl_trait() - | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias` - --> $DIR/error-in-impl-trait.rs:15:5 - | -LL | error::_in::impl_trait::alias(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` - --> $DIR/error-in-impl-trait.rs:17:9 - | -LL | (|| error::_in::impl_trait::alias::nested::closure())() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn` - --> $DIR/error-in-impl-trait.rs:26:5 - | -LL | error::_in::async_fn() - | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn` - | - = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/README.md b/src/test/rustdoc-ui/error-in-impl-trait/README.md new file mode 100644 index 0000000000000..1176a4a8c4cf8 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/README.md @@ -0,0 +1,7 @@ +Each of these needs to be in a separate file, +because the `delay_span_bug` ICE in rustdoc won't be triggerred +if even a single other error was emitted. + +However, conceptually they are all testing basically the same thing. +See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128 +for more details. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs new file mode 100644 index 0000000000000..112a2c494a5c2 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.rs @@ -0,0 +1,10 @@ +// edition:2018 + +/// This used to work with ResolveBodyWithLoop. +/// However now that we ignore type checking instead of modifying the function body, +/// the return type is seen as `impl Future`, not a `u32`. +/// So it no longer allows errors in the function body. +pub async fn a() -> u32 { + error::_in::async_fn() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr new file mode 100644 index 0000000000000..eae3cadf653e1 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn` + --> $DIR/async.rs:8:5 + | +LL | error::_in::async_fn() + | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs new file mode 100644 index 0000000000000..df40c121d579e --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs @@ -0,0 +1,5 @@ +// manually desugared version of an `async fn` (but with a closure instead of a generator) +pub fn a() -> impl Fn() -> u32 { + || content::doesnt::matter() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr new file mode 100644 index 0000000000000..9355165997ac9 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `content::doesnt::matter` + --> $DIR/closure.rs:3:8 + | +LL | || content::doesnt::matter() + | ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs new file mode 100644 index 0000000000000..399fb827517fa --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs @@ -0,0 +1,6 @@ +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + (|| error::_in::impl_trait::alias::nested::closure())() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr new file mode 100644 index 0000000000000..569f2ab8ff8ea --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` + --> $DIR/impl-keyword-closure.rs:4:9 + | +LL | (|| error::_in::impl_trait::alias::nested::closure())() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs new file mode 100644 index 0000000000000..24b5734dbd0bf --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs @@ -0,0 +1,6 @@ +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + error::_in::impl_trait() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr new file mode 100644 index 0000000000000..68bc71f90b288 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait` + --> $DIR/impl-keyword.rs:4:5 + | +LL | error::_in::impl_trait() + | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs new file mode 100644 index 0000000000000..1498fa4f890d0 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + (|| error::_in::impl_trait::alias::nested::closure())() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr new file mode 100644 index 0000000000000..f3edb0385c821 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure` + --> $DIR/trait-alias-closure.rs:8:9 + | +LL | (|| error::_in::impl_trait::alias::nested::closure())() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs new file mode 100644 index 0000000000000..cf9bc48c7f872 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] + +pub trait ValidTrait {} +type ImplTrait = impl ValidTrait; + +/// This returns impl trait, but using a type alias +pub fn h() -> ImplTrait { + error::_in::impl_trait::alias() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr new file mode 100644 index 0000000000000..ddb0fb88cc7fa --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias` + --> $DIR/trait-alias.rs:8:5 + | +LL | error::_in::impl_trait::alias() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. From d01044305a5f2eb177521f51a7d7bfaee1ccf688 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 9 Jul 2020 10:30:34 -0400 Subject: [PATCH 20/69] Add test case for #65863 --- src/test/rustdoc/return-impl-trait.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/test/rustdoc/return-impl-trait.rs diff --git a/src/test/rustdoc/return-impl-trait.rs b/src/test/rustdoc/return-impl-trait.rs new file mode 100644 index 0000000000000..1ccf5ac46119a --- /dev/null +++ b/src/test/rustdoc/return-impl-trait.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +pub trait Backend {} + +impl Backend for () {} + +pub struct Module(T); + +pub type BackendImpl = impl Backend; + +// @has return_impl_trait/fn.make_module.html +/// Documentation +pub fn make_module() -> Module { + Module(()) +} From cf844d2eabc8929edb0923d71ec6ff076ac3428b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 9 Jul 2020 22:11:15 -0400 Subject: [PATCH 21/69] Don't make typeck_tables_of public --- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/core.rs | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 514600b4733d4..bc01da324b66f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -955,7 +955,7 @@ where val.fold_with(&mut FixupFolder { tcx }) } -pub fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> { +fn typeck_tables_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckTables<'tcx> { let fallback = move || tcx.type_of(def_id.to_def_id()); typeck_tables_of_with_fallback(tcx, def_id, fallback) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 79e1585ce3cdb..9ba2545ba63cb 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -78,7 +78,7 @@ extern crate rustc_middle; pub mod expr_use_visitor; mod astconv; -pub mod check; +mod check; mod check_unused; mod coherence; mod collect; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 413faff283e19..78b4456ba9c6c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -375,7 +375,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt override_queries: Some(|_sess, local_providers, external_providers| { local_providers.lint_mod = |_, _| {}; external_providers.lint_mod = |_, _| {}; - //let old_typeck = local_providers.typeck_tables_of; local_providers.typeck_tables_of = move |tcx, def_id| { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". @@ -389,8 +388,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); debug!("visiting body for {:?}", def_id); EmitIgnoredResolutionErrors::new(&tcx.sess, hir).visit_body(body); - rustc_typeck::check::typeck_tables_of(tcx, def_id) - //DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) + DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) }; }), registry: rustc_driver::diagnostics_registry(), @@ -596,13 +594,11 @@ use rustc_hir::{ }; use rustc_middle::hir::map::Map; -/* thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx>, rustc_span::def_id::LocalDefId) -> &'tcx rustc_middle::ty::TypeckTables<'tcx> = { let mut providers = rustc_middle::ty::query::Providers::default(); rustc_typeck::provide(&mut providers); providers.typeck_tables_of }); -*/ /// Due to https://github.com/rust-lang/rust/pull/73566, /// the name resolution pass may find errors that are never emitted. From 0cbc1cddcc6b9657fb727e35dce753d38e52cc52 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 10 Jul 2020 16:55:06 -0400 Subject: [PATCH 22/69] Avoid unnecessary enum Just use a boolean instead. --- src/librustc_interface/passes.rs | 7 +--- src/librustc_resolve/late.rs | 56 ++++++++++---------------------- src/librustc_resolve/lib.rs | 5 ++- 3 files changed, 20 insertions(+), 48 deletions(-) diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 690ed9decb9ef..6505803eba8c6 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -233,8 +233,6 @@ fn configure_and_expand_inner<'a>( resolver_arenas: &'a ResolverArenas<'a>, metadata_loader: &'a MetadataLoaderDyn, ) -> Result<(ast::Crate, Resolver<'a>)> { - use rustc_resolve::IgnoreState; - log::trace!("configure_and_expand_inner"); pre_expansion_lint(sess, lint_store, &krate); @@ -413,10 +411,7 @@ fn configure_and_expand_inner<'a>( println!("{}", json::as_json(&krate)); } - // If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items. - let ignore_bodies = - if sess.opts.actually_rustdoc { IgnoreState::Ignore } else { IgnoreState::Report }; - resolver.resolve_crate(&krate, ignore_bodies); + resolver.resolve_crate(&krate); // Needs to go *after* expansion to be able to check the results of macro expansion. sess.time("complete_gated_feature_checking", || { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 637326bb88d86..528444b0e9894 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -376,19 +376,6 @@ struct DiagnosticMetadata<'ast> { current_let_binding: Option<(Span, Option, Option)>, } -/// Keeps track of whether errors should be reported. -/// -/// Used by rustdoc to ignore errors in function bodies. -/// This is just a fancy boolean so it can have doc-comments. -#[derive(Copy, Clone, Debug)] -pub enum IgnoreState { - /// We are at global scope or in a trait implementation, so all errors should be reported. - Report, - /// We are in a function body, so errors shouldn't be reported. - Ignore, - // Note that we don't need to worry about macros, which must always be resolved (or we wouldn't have gotten to the late pass). -} - struct LateResolutionVisitor<'a, 'b, 'ast> { r: &'b mut Resolver<'a>, @@ -408,12 +395,12 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// Fields used to add information to diagnostic errors. diagnostic_metadata: DiagnosticMetadata<'ast>, - /// State used to know whether to ignore resolution errors for item bodies. + /// State used to know whether to ignore resolution errors for function bodies. /// /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items. /// In most cases this will be `None`, in which case errors will always be reported. /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body. - ignore_bodies: Option, + in_func_body: bool, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. @@ -517,10 +504,10 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_fn_ret_ty(this, &declaration.output); - let previous_ignore = this.ignore_bodies.take(); - // Ignore errors in function bodies if originally passed `ignore_state: true` + let previous_state = this.in_func_body; + // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. - this.ignore_bodies = previous_ignore.and(Some(IgnoreState::Ignore)); + this.in_func_body = true; // Resolve the function body, potentially inside the body of an async closure match fn_kind { FnKind::Fn(.., body) => walk_list!(this, visit_block, body), @@ -528,7 +515,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }; debug!("(resolving function) leaving function"); - this.ignore_bodies = previous_ignore; + this.in_func_body = previous_state; }) }); self.diagnostic_metadata.current_function = previous_value; @@ -652,10 +639,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { - fn new( - resolver: &'b mut Resolver<'a>, - ignore_bodies: IgnoreState, - ) -> LateResolutionVisitor<'a, 'b, 'ast> { + fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; @@ -672,11 +656,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { label_ribs: Vec::new(), current_trait_ref: None, diagnostic_metadata: DiagnosticMetadata::default(), - ignore_bodies: match ignore_bodies { - // errors at module scope should always be reported - IgnoreState::Ignore => Some(IgnoreState::Report), - IgnoreState::Report => None, - }, + // errors at module scope should always be reported + in_func_body: false, } } @@ -1194,9 +1175,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_items: &'ast [P], ) { debug!("resolve_implementation"); - let old_ignore = self.ignore_bodies.take(); + let old_ignore = self.in_func_body; // Never ignore errors in trait implementations. - self.ignore_bodies = old_ignore.and(Some(IgnoreState::Report)); + self.in_func_body = false; // If applicable, create a rib for the type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { // Dummy self type for better errors if `Self` is used in the trait path. @@ -1292,7 +1273,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); }); }); - self.ignore_bodies = old_ignore; + self.in_func_body = old_ignore; } fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) @@ -1900,7 +1881,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { /// A wrapper around [`Resolver::report_error`]. /// - /// This doesn't emit errors for function bodies if `ignore_bodies` is set. + /// This doesn't emit errors for function bodies if this is r fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) { if self.should_report_errs() { self.r.report_error(span, resolution_error); @@ -1908,12 +1889,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } #[inline] + /// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items. fn should_report_errs(&self) -> bool { - debug!("should_report_errs(state={:?})", self.ignore_bodies); - match self.ignore_bodies { - None | Some(IgnoreState::Report) => true, - Some(IgnoreState::Ignore) => false, - } + !(self.r.session.opts.actually_rustdoc && self.in_func_body) } // Resolve in alternative namespaces if resolution in the primary namespace fails. @@ -2412,8 +2390,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } impl<'a> Resolver<'a> { - pub(crate) fn late_resolve_crate(&mut self, krate: &Crate, ignore_bodies: IgnoreState) { - let mut late_resolution_visitor = LateResolutionVisitor::new(self, ignore_bodies); + pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { + let mut late_resolution_visitor = LateResolutionVisitor::new(self); visit::walk_crate(&mut late_resolution_visitor, krate); for (id, span) in late_resolution_visitor.diagnostic_metadata.unused_labels.iter() { self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label"); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 23bd0028bd1dd..a265c15c18bc9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -15,7 +15,6 @@ #![feature(or_patterns)] #![recursion_limit = "256"] -pub use late::IgnoreState; pub use rustc_hir::def::{Namespace, PerNS}; use Determinacy::*; @@ -1442,13 +1441,13 @@ impl<'a> Resolver<'a> { } /// Entry point to crate resolution. - pub fn resolve_crate(&mut self, krate: &Crate, ignore_bodies: IgnoreState) { + pub fn resolve_crate(&mut self, krate: &Crate) { let _prof_timer = self.session.prof.generic_activity("resolve_crate"); ImportResolver { r: self }.finalize_imports(); self.finalize_macro_resolutions(); - self.late_resolve_crate(krate, ignore_bodies); + self.late_resolve_crate(krate); self.check_unused(krate); self.report_errors(krate); From 3576f5d7e153d10aae36b2be067bc6243a4c77db Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 10 Jul 2020 17:24:17 -0400 Subject: [PATCH 23/69] Address review comments about code style --- src/librustdoc/core.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 78b4456ba9c6c..d5389d06906b8 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -5,13 +5,18 @@ use rustc_driver::abort_on_err; use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::json::JsonEmitter; use rustc_feature::UnstableFeatures; -use rustc_hir::def::Namespace::TypeNS; +use rustc_hir::def::{Namespace::TypeNS, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::HirId; +use rustc_hir::{ + intravisit::{NestedVisitorMap, Visitor}, + Path, +}; use rustc_interface::interface; +use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::CrateStore; use rustc_middle::middle::privacy::AccessLevels; -use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_resolve as resolve; use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::lint; @@ -587,15 +592,8 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }) } -use rustc_hir::def::Res; -use rustc_hir::{ - intravisit::{NestedVisitorMap, Visitor}, - Path, -}; -use rustc_middle::hir::map::Map; - -thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(rustc_middle::ty::TyCtxt<'tcx>, rustc_span::def_id::LocalDefId) -> &'tcx rustc_middle::ty::TypeckTables<'tcx> = { - let mut providers = rustc_middle::ty::query::Providers::default(); +thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(TyCtxt<'tcx>, LocalDefId) -> &'tcx ty::TypeckTables<'tcx> = { + let mut providers = ty::query::Providers::default(); rustc_typeck::provide(&mut providers); providers.typeck_tables_of }); @@ -625,13 +623,11 @@ impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { } fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) { - log::debug!("visiting path {:?}", path); + debug!("visiting path {:?}", path); if path.res == Res::Err { // We have less context here than in rustc_resolve, // so we can only emit the name and span. // However we can give a hint that rustc_resolve will have more info. - // NOTE: this is a very rare case (only 4 out of several hundred thousand crates in a crater run) - // NOTE: so it's ok for it to be slow let label = format!( "could not resolve path `{}`", path.segments From bbe4971095717912463d8dbc00ba8ce9a5988963 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 10 Jul 2020 17:50:03 -0400 Subject: [PATCH 24/69] Don't crash on Vec --- src/librustdoc/core.rs | 9 ++++++--- .../rustdoc-ui/error-in-impl-trait/generic-argument.rs | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index d5389d06906b8..adc6b536699eb 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -9,7 +9,7 @@ use rustc_hir::def::{Namespace::TypeNS, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::HirId; use rustc_hir::{ - intravisit::{NestedVisitorMap, Visitor}, + intravisit::{self, NestedVisitorMap, Visitor}, Path, }; use rustc_interface::interface; @@ -622,7 +622,7 @@ impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { NestedVisitorMap::OnlyBodies(self.hir_map) } - fn visit_path(&mut self, path: &'v Path<'v>, _id: HirId) { + fn visit_path(&mut self, path: &'hir Path<'_>, _id: HirId) { debug!("visiting path {:?}", path); if path.res == Res::Err { // We have less context here than in rustc_resolve, @@ -648,7 +648,10 @@ impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { err.note("try running again with `rustc` and you may get a more detailed error"); err.emit(); } - // NOTE: this does _not_ visit the path segments + // We could have an outer resolution that succeeded, + // but with generic parameters that failed. + // Recurse into the segments so we catch those too. + intravisit::walk_path(self, path); } } diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs new file mode 100644 index 0000000000000..0ccf2e3866fc9 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs @@ -0,0 +1,7 @@ +trait ValidTrait {} + +/// This has docs +pub fn f() -> impl ValidTrait { + Vec::::new() + //~^ ERROR failed to resolve +} From 2f29e696ab0ced54f016bed0514a53f6e281ac8a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 10 Jul 2020 17:51:38 -0400 Subject: [PATCH 25/69] Mention `cargo check` in help message --- src/librustdoc/core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index adc6b536699eb..bdacf608ff59d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -645,7 +645,7 @@ impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { ); err.span_label(path.span, label); err.note("this error was originally ignored because you are running `rustdoc`"); - err.note("try running again with `rustc` and you may get a more detailed error"); + err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error"); err.emit(); } // We could have an outer resolution that succeeded, From 763d373dabb7ccf581737749a2a1adec335d8249 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 10 Jul 2020 17:59:29 -0400 Subject: [PATCH 26/69] Use tcx as the only context for visitor Previously two different parts of the context had to be passed separately; there were two sources of truth. --- src/librustdoc/core.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index bdacf608ff59d..b87d7b19dcd5e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -392,7 +392,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); debug!("visiting body for {:?}", def_id); - EmitIgnoredResolutionErrors::new(&tcx.sess, hir).visit_body(body); + EmitIgnoredResolutionErrors::new(&tcx).visit_body(body); DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) }; }), @@ -602,27 +602,26 @@ thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(TyCtxt<'tcx>, LocalDefId) -> & /// the name resolution pass may find errors that are never emitted. /// If typeck is called after this happens, then we'll get an ICE: /// 'Res::Error found but not reported'. To avoid this, emit the errors now. -struct EmitIgnoredResolutionErrors<'a, 'hir> { - session: &'a Session, - hir_map: Map<'hir>, +struct EmitIgnoredResolutionErrors<'a, 'tcx> { + tcx: &'a TyCtxt<'tcx>, } -impl<'a, 'hir> EmitIgnoredResolutionErrors<'a, 'hir> { - fn new(session: &'a Session, hir_map: Map<'hir>) -> Self { - Self { session, hir_map } +impl<'a, 'tcx> EmitIgnoredResolutionErrors<'a, 'tcx> { + fn new(tcx: &'a TyCtxt<'tcx>) -> Self { + Self { tcx } } } -impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { - type Map = Map<'hir>; +impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'_, 'tcx> { + type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { // We need to recurse into nested closures, // since those will fallback to the parent for type checking. - NestedVisitorMap::OnlyBodies(self.hir_map) + NestedVisitorMap::OnlyBodies(self.tcx.hir()) } - fn visit_path(&mut self, path: &'hir Path<'_>, _id: HirId) { + fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) { debug!("visiting path {:?}", path); if path.res == Res::Err { // We have less context here than in rustc_resolve, @@ -637,7 +636,7 @@ impl<'hir> Visitor<'hir> for EmitIgnoredResolutionErrors<'_, 'hir> { .join("::") ); let mut err = rustc_errors::struct_span_err!( - self.session, + self.tcx.sess, path.span, E0433, "failed to resolve: {}", From 0759a55feff2d7c4a15b563adc087ac4f59acb1b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 10 Jul 2020 18:07:31 -0400 Subject: [PATCH 27/69] Remove unnecessary lifetime parameter TyCtxt is a reference type and so can be passed by value. --- src/librustdoc/core.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b87d7b19dcd5e..39c214b1fb42b 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -392,7 +392,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let hir = tcx.hir(); let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); debug!("visiting body for {:?}", def_id); - EmitIgnoredResolutionErrors::new(&tcx).visit_body(body); + EmitIgnoredResolutionErrors::new(tcx).visit_body(body); DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) }; }), @@ -602,17 +602,17 @@ thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(TyCtxt<'tcx>, LocalDefId) -> & /// the name resolution pass may find errors that are never emitted. /// If typeck is called after this happens, then we'll get an ICE: /// 'Res::Error found but not reported'. To avoid this, emit the errors now. -struct EmitIgnoredResolutionErrors<'a, 'tcx> { - tcx: &'a TyCtxt<'tcx>, +struct EmitIgnoredResolutionErrors<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'a, 'tcx> EmitIgnoredResolutionErrors<'a, 'tcx> { - fn new(tcx: &'a TyCtxt<'tcx>) -> Self { +impl<'tcx> EmitIgnoredResolutionErrors<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Self { Self { tcx } } } -impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'_, 'tcx> { +impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> NestedVisitorMap { From 2d0e8e2162a2e2be233a63ba5a8cbf3e19770b17 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 10 Jul 2020 19:00:33 -0400 Subject: [PATCH 28/69] --bless --- src/test/rustdoc-ui/error-in-impl-trait/async.stderr | 2 +- .../rustdoc-ui/error-in-impl-trait/closure.stderr | 2 +- .../error-in-impl-trait/generic-argument.stderr | 12 ++++++++++++ .../error-in-impl-trait/impl-keyword-closure.stderr | 2 +- .../error-in-impl-trait/impl-keyword.stderr | 2 +- .../error-in-impl-trait/trait-alias-closure.stderr | 2 +- .../error-in-impl-trait/trait-alias.stderr | 2 +- 7 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr index eae3cadf653e1..086db1be72274 100644 --- a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr @@ -5,7 +5,7 @@ LL | error::_in::async_fn() | ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn` | = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error error: aborting due to previous error diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr index 9355165997ac9..4ee9c4d1f438d 100644 --- a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr @@ -5,7 +5,7 @@ LL | || content::doesnt::matter() | ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter` | = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error error: aborting due to previous error diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr new file mode 100644 index 0000000000000..72716c258dc1e --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `DoesNotExist` + --> $DIR/generic-argument.rs:5:11 + | +LL | Vec::::new() + | ^^^^^^^^^^^^ could not resolve path `DoesNotExist` + | + = note: this error was originally ignored because you are running `rustdoc` + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr index 569f2ab8ff8ea..55f9b609a1105 100644 --- a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr @@ -5,7 +5,7 @@ LL | (|| error::_in::impl_trait::alias::nested::closure())() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` | = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error error: aborting due to previous error diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr index 68bc71f90b288..3257079f94219 100644 --- a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr @@ -5,7 +5,7 @@ LL | error::_in::impl_trait() | ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait` | = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error error: aborting due to previous error diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr index f3edb0385c821..84b28139dbcd5 100644 --- a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr @@ -5,7 +5,7 @@ LL | (|| error::_in::impl_trait::alias::nested::closure())() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure` | = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error error: aborting due to previous error diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr index ddb0fb88cc7fa..9be6a3d8d6bba 100644 --- a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr @@ -5,7 +5,7 @@ LL | error::_in::impl_trait::alias() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias` | = note: this error was originally ignored because you are running `rustdoc` - = note: try running again with `rustc` and you may get a more detailed error + = note: try running again with `rustc` or `cargo check` and you may get a more detailed error error: aborting due to previous error From 02a24c8e2fd370041a24b7d93e8c3710b7b76015 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 11 Jul 2020 00:28:42 -0400 Subject: [PATCH 29/69] Don't ICE on infinitely recursive types `evaluate_obligation` can only be run on types that are already valid. So rustdoc still has to run typeck even though it doesn't care about the result. --- Cargo.lock | 1 + src/librustdoc/Cargo.toml | 1 + src/librustdoc/core.rs | 15 +++++++++++++++ src/librustdoc/lib.rs | 2 ++ src/test/rustdoc-ui/infinite-recursive-type.rs | 4 ++++ .../rustdoc-ui/infinite-recursive-type.stderr | 17 +++++++++++++++++ 6 files changed, 40 insertions(+) create mode 100644 src/test/rustdoc-ui/infinite-recursive-type.rs create mode 100644 src/test/rustdoc-ui/infinite-recursive-type.stderr diff --git a/Cargo.lock b/Cargo.lock index 5309c03ee23ae..992421dcd7abb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4027,6 +4027,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "itertools 0.8.0", + "lazy_static", "minifier", "pulldown-cmark", "rustc-rayon", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 4af13e4cd587a..baceb13cc6141 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -16,3 +16,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tempfile = "3" itertools = "0.8" +lazy_static = "1" diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 39c214b1fb42b..a77b177bd2864 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -364,6 +364,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt ..Options::default() }; + lazy_static! { + static ref EMPTY_MAP: FxHashSet = FxHashSet::default(); + } let config = interface::Config { opts: sessopts, crate_cfg: interface::parse_cfgspecs(cfgs), @@ -378,8 +381,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt lint_caps, register_lints: None, override_queries: Some(|_sess, local_providers, external_providers| { + // Most lints will require typechecking, so just don't run them. local_providers.lint_mod = |_, _| {}; external_providers.lint_mod = |_, _| {}; + local_providers.typeck_item_bodies = |_, _| {}; + // hack so that `used_trait_imports` won't try to call typeck_tables_of + local_providers.used_trait_imports = |_, _| &EMPTY_MAP; + // In case typeck does end up being called, don't ICE in case there were name resolution errors local_providers.typeck_tables_of = move |tcx, def_id| { // Closures' tables come from their outermost function, // as they are part of the same "inference environment". @@ -439,6 +447,13 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); global_ctxt.enter(|tcx| { + // Some queries require that they only run on valid types: + // https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425 + // Therefore typecheck this crate before running lints. + // NOTE: this does not typeck item bodies or run the default rustc lints + // (see `override_queries` in the `config`) + let _ = rustc_typeck::check_crate(tcx); + tcx.sess.abort_if_errors(); sess.time("missing_docs", || { rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new); }); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4bd6b1260ccef..cbf53d52ef009 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -15,6 +15,8 @@ #![recursion_limit = "256"] extern crate env_logger; +#[macro_use] +extern crate lazy_static; extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; diff --git a/src/test/rustdoc-ui/infinite-recursive-type.rs b/src/test/rustdoc-ui/infinite-recursive-type.rs new file mode 100644 index 0000000000000..32793fc4f76c0 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.rs @@ -0,0 +1,4 @@ +enum E { +//~^ ERROR recursive type `E` has infinite size + V(E), +} diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr new file mode 100644 index 0000000000000..897445f200cb7 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `E` has infinite size + --> $DIR/infinite-recursive-type.rs:1:1 + | +LL | enum E { + | ^^^^^^ recursive type has infinite size +LL | +LL | V(E), + | - recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable + | +LL | V(Box), + | ^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. From 4c88070c87b81c3cf6c8409a78c35ebdf67a67c3 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 11 Jul 2020 08:48:25 -0400 Subject: [PATCH 30/69] Use mem::replace instead of rewriting it --- src/librustc_resolve/late.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 528444b0e9894..63b238faff615 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -504,10 +504,9 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_fn_ret_ty(this, &declaration.output); - let previous_state = this.in_func_body; // Ignore errors in function bodies if this is rustdoc // Be sure not to set this until the function signature has been resolved. - this.in_func_body = true; + let previous_state = replace(&mut this.in_func_body, true); // Resolve the function body, potentially inside the body of an async closure match fn_kind { FnKind::Fn(.., body) => walk_list!(this, visit_block, body), @@ -1175,9 +1174,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_items: &'ast [P], ) { debug!("resolve_implementation"); - let old_ignore = self.in_func_body; // Never ignore errors in trait implementations. - self.in_func_body = false; + let old_ignore = replace(&mut self.in_func_body, false); // If applicable, create a rib for the type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { // Dummy self type for better errors if `Self` is used in the trait path. From b2ff0e703eef715737ebb2afab04ec3f73cbf4bf Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 11 Jul 2020 08:52:36 -0400 Subject: [PATCH 31/69] Fix comment --- src/librustc_resolve/late.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 63b238faff615..2df68624a369b 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1879,7 +1879,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { /// A wrapper around [`Resolver::report_error`]. /// - /// This doesn't emit errors for function bodies if this is r + /// This doesn't emit errors for function bodies if this is rustdoc. fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) { if self.should_report_errs() { self.r.report_error(span, resolution_error); From ac9157b482e916c09e2ec35bb7e514ae7b6b9c03 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 11 Jul 2020 20:54:47 -0400 Subject: [PATCH 32/69] EMPTY_MAP -> EMPTY_SET --- src/librustdoc/core.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a77b177bd2864..f433c78890ffa 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -364,9 +364,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt ..Options::default() }; - lazy_static! { - static ref EMPTY_MAP: FxHashSet = FxHashSet::default(); - } let config = interface::Config { opts: sessopts, crate_cfg: interface::parse_cfgspecs(cfgs), @@ -381,12 +378,15 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt lint_caps, register_lints: None, override_queries: Some(|_sess, local_providers, external_providers| { + lazy_static! { + static ref EMPTY_SET: FxHashSet = FxHashSet::default(); + } // Most lints will require typechecking, so just don't run them. local_providers.lint_mod = |_, _| {}; external_providers.lint_mod = |_, _| {}; local_providers.typeck_item_bodies = |_, _| {}; // hack so that `used_trait_imports` won't try to call typeck_tables_of - local_providers.used_trait_imports = |_, _| &EMPTY_MAP; + local_providers.used_trait_imports = |_, _| &EMPTY_SET; // In case typeck does end up being called, don't ICE in case there were name resolution errors local_providers.typeck_tables_of = move |tcx, def_id| { // Closures' tables come from their outermost function, From 6eec9fb5d15d2bb2025398f5cae12aebe03d87e8 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 11 Jul 2020 21:50:25 -0400 Subject: [PATCH 33/69] Address review comments - Move static variables into the innermost scope in which they are used - Clean up comments - Remove external_providers; rename local_providers -> providers --- src/librustdoc/core.rs | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index f433c78890ffa..c2d0bd103eca9 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -377,18 +377,26 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt crate_name, lint_caps, register_lints: None, - override_queries: Some(|_sess, local_providers, external_providers| { - lazy_static! { - static ref EMPTY_SET: FxHashSet = FxHashSet::default(); - } + override_queries: Some(|_sess, providers, _external_providers| { // Most lints will require typechecking, so just don't run them. - local_providers.lint_mod = |_, _| {}; - external_providers.lint_mod = |_, _| {}; - local_providers.typeck_item_bodies = |_, _| {}; + providers.lint_mod = |_, _| {}; + // Prevent `rustc_typeck::check_crate` from calling `typeck_tables_of` on all bodies. + providers.typeck_item_bodies = |_, _| {}; // hack so that `used_trait_imports` won't try to call typeck_tables_of - local_providers.used_trait_imports = |_, _| &EMPTY_SET; + providers.used_trait_imports = |_, _| { + lazy_static! { + static ref EMPTY_SET: FxHashSet = FxHashSet::default(); + } + &EMPTY_SET + }; // In case typeck does end up being called, don't ICE in case there were name resolution errors - local_providers.typeck_tables_of = move |tcx, def_id| { + providers.typeck_tables_of = move |tcx, def_id| { + thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(TyCtxt<'tcx>, LocalDefId) -> &'tcx ty::TypeckTables<'tcx> = { + let mut providers = ty::query::Providers::default(); + rustc_typeck::provide(&mut providers); + providers.typeck_tables_of + }); + // Closures' tables come from their outermost function, // as they are part of the same "inference environment". // This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`) @@ -447,10 +455,11 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take(); global_ctxt.enter(|tcx| { - // Some queries require that they only run on valid types: - // https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425 - // Therefore typecheck this crate before running lints. - // NOTE: this does not typeck item bodies or run the default rustc lints + // 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. + // NOTE: this does not call `tcx.analysis()` so that we won't + // typeck function bodies or run the default rustc lints. // (see `override_queries` in the `config`) let _ = rustc_typeck::check_crate(tcx); tcx.sess.abort_if_errors(); @@ -607,12 +616,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }) } -thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(TyCtxt<'tcx>, LocalDefId) -> &'tcx ty::TypeckTables<'tcx> = { - let mut providers = ty::query::Providers::default(); - rustc_typeck::provide(&mut providers); - providers.typeck_tables_of -}); - /// Due to https://github.com/rust-lang/rust/pull/73566, /// the name resolution pass may find errors that are never emitted. /// If typeck is called after this happens, then we'll get an ICE: From e117b47f759e93679192256043db67f8f8a68675 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 14 Jul 2020 21:14:09 -0400 Subject: [PATCH 34/69] Catch errors for any new item, not just trait implementations This matches the previous behavior of everybody_loops and is also more consistent than special-casing impls. --- src/librustc_resolve/late.rs | 6 +++--- src/test/rustdoc-ui/impl-fn-nesting.rs | 4 ++-- src/test/rustdoc-ui/impl-fn-nesting.stderr | 8 +++++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 2df68624a369b..274f93dd50b0d 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -407,7 +407,10 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_item(&mut self, item: &'ast Item) { let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item)); + // Always report errors in items we just entered. + let old_ignore = replace(&mut self.in_func_body, false); self.resolve_item(item); + self.in_func_body = old_ignore; self.diagnostic_metadata.current_item = prev; } fn visit_arm(&mut self, arm: &'ast Arm) { @@ -1174,8 +1177,6 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { impl_items: &'ast [P], ) { debug!("resolve_implementation"); - // Never ignore errors in trait implementations. - let old_ignore = replace(&mut self.in_func_body, false); // If applicable, create a rib for the type parameters. self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { // Dummy self type for better errors if `Self` is used in the trait path. @@ -1271,7 +1272,6 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }); }); }); - self.in_func_body = old_ignore; } fn check_trait_item(&mut self, ident: Ident, ns: Namespace, span: Span, err: F) diff --git a/src/test/rustdoc-ui/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs index d2dd8d835fd79..a927f6bd79976 100644 --- a/src/test/rustdoc-ui/impl-fn-nesting.rs +++ b/src/test/rustdoc-ui/impl-fn-nesting.rs @@ -41,8 +41,8 @@ pub fn f(a: UnknownType, b: B) { can_define_macros_here_too!(); /// This also is documented. - pub fn doubly_nested(c: UnknownTypeShouldBeIgnored) { - + pub fn doubly_nested(c: UnknownType) { + //~^ ERROR cannot find type `UnknownType` in this scope } } } diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr index f8629964c0701..608749af895ed 100644 --- a/src/test/rustdoc-ui/impl-fn-nesting.stderr +++ b/src/test/rustdoc-ui/impl-fn-nesting.stderr @@ -52,9 +52,15 @@ error[E0412]: cannot find type `UnknownType` in this scope LL | type Item = UnknownType; | ^^^^^^^^^^^ not found in this scope +error[E0412]: cannot find type `UnknownType` in this scope + --> $DIR/impl-fn-nesting.rs:44:37 + | +LL | pub fn doubly_nested(c: UnknownType) { + | ^^^^^^^^^^^ not found in this scope + error: Compilation failed, aborting rustdoc -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors Some errors have detailed explanations: E0405, E0412. For more information about an error, try `rustc --explain E0405`. From 281ca139161fd6a208f2d531f683a706e8286826 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 15 Jul 2020 10:42:18 -0400 Subject: [PATCH 35/69] Use the default providers in rustc_interface instead of adding our own This avoids duplicating the same struct twice. --- src/librustdoc/core.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c2d0bd103eca9..00315675fafe3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -16,7 +16,7 @@ use rustc_interface::interface; use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::CrateStore; use rustc_middle::middle::privacy::AccessLevels; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_resolve as resolve; use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::lint; @@ -391,12 +391,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }; // In case typeck does end up being called, don't ICE in case there were name resolution errors providers.typeck_tables_of = move |tcx, def_id| { - thread_local!(static DEFAULT_TYPECK: for<'tcx> fn(TyCtxt<'tcx>, LocalDefId) -> &'tcx ty::TypeckTables<'tcx> = { - let mut providers = ty::query::Providers::default(); - rustc_typeck::provide(&mut providers); - providers.typeck_tables_of - }); - // Closures' tables come from their outermost function, // as they are part of the same "inference environment". // This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`) @@ -409,7 +403,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id))); debug!("visiting body for {:?}", def_id); EmitIgnoredResolutionErrors::new(tcx).visit_body(body); - DEFAULT_TYPECK.with(|typeck| typeck(tcx, def_id)) + (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck_tables_of)(tcx, def_id) }; }), registry: rustc_driver::diagnostics_registry(), From 703f6803db4b2014486a1c7230bc965fd75a672e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 10 Jul 2020 19:00:38 +0200 Subject: [PATCH 36/69] Don't panic if the lhs of a div by zero is not statically known --- src/librustc_mir/transform/const_prop.rs | 26 +++++++++++++++---- .../const_prop/ice-assert-fail-div-by-zero.rs | 11 +++++--- .../ice-assert-fail-div-by-zero.stderr | 14 ++++++++++ 3 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index fbe3377d87500..237a5a64f8bf8 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -484,7 +484,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { lint: &'static lint::Lint, source_info: SourceInfo, message: &'static str, - panic: AssertKind, + panic: AssertKind, ) -> Option<()> { let lint_root = self.lint_root(source_info)?; self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| { @@ -1004,11 +1004,27 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected)); let value_const = self.ecx.read_scalar(value).unwrap(); if expected != value_const { + enum DbgVal { + Val(T), + Underscore, + } + impl std::fmt::Debug for DbgVal { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Val(val) => val.fmt(fmt), + Self::Underscore => fmt.write_str("_"), + } + } + } let mut eval_to_int = |op| { - let op = self - .eval_operand(op, source_info) - .expect("if we got here, it must be const"); - self.ecx.read_immediate(op).unwrap().to_const_int() + // This can be `None` if the lhs wasn't const propagated and we just + // triggered the assert on the value of the rhs. + match self.eval_operand(op, source_info) { + Some(op) => { + DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int()) + } + None => DbgVal::Underscore, + } }; let msg = match msg { AssertKind::DivisionByZero(op) => { diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs index 5f2d5e80243fe..d19cf00eb9ce4 100644 --- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs @@ -1,9 +1,12 @@ // check-pass +// compile-flags: --crate-type lib + +#![warn(unconditional_panic)] + pub struct Fixed64(i64); -pub fn div(f: Fixed64) { - f.0 / 0; +// HACK: this test passes only because this is a const fn that is written to metadata +pub const fn div(f: Fixed64) { + f.0 / 0; //~ WARN will panic at runtime } - -fn main() {} diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr new file mode 100644 index 0000000000000..e2a3e4db8abd1 --- /dev/null +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr @@ -0,0 +1,14 @@ +warning: this operation will panic at runtime + --> $DIR/ice-assert-fail-div-by-zero.rs:11:5 + | +LL | f.0 / 0; + | ^^^^^^^ attempt to divide _ by zero + | +note: the lint level is defined here + --> $DIR/ice-assert-fail-div-by-zero.rs:5:9 + | +LL | #![warn(unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + From 593c7fe6d6b44c87df07d62996cf575fb3f62ce9 Mon Sep 17 00:00:00 2001 From: ColoredCarrot Date: Thu, 16 Jul 2020 11:04:01 +0200 Subject: [PATCH 37/69] Fix typo in std::mem::transmute documentation u32::from_ge_bytes method does not exist; replace with u32::from_be_bytes --- src/libcore/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 540a8cfb290b3..45b636b0089b2 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1126,7 +1126,7 @@ extern "rust-intrinsic" { /// /// // use `u32::from_ne_bytes` instead /// let num = u32::from_ne_bytes(raw_bytes); - /// // or use `u32::from_le_bytes` or `u32::from_ge_bytes` to specify the endianness + /// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness /// let num = u32::from_le_bytes(raw_bytes); /// assert_eq!(num, 0x12345678); /// let num = u32::from_be_bytes(raw_bytes); From 338a27174a0bd900e573b2ee0e7383244a8b0bf9 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 8 Jul 2020 22:16:18 +0200 Subject: [PATCH 38/69] forbid generic params in the type of const params --- src/librustc_error_codes/error_codes.rs | 1 + src/librustc_error_codes/error_codes/E0671.md | 2 +- src/librustc_error_codes/error_codes/E0770.md | 15 +++++++++ src/librustc_resolve/diagnostics.rs | 10 ++++++ src/librustc_resolve/late.rs | 14 +++++++-- src/librustc_resolve/lib.rs | 28 ++++++++++++++++- ...const-param-type-depends-on-const-param.rs | 13 ++++++++ ...t-param-type-depends-on-const-param.stderr | 31 +++++++++++++++++++ ...aram-type-depends-on-type-param-ungated.rs | 2 +- ...-type-depends-on-type-param-ungated.stderr | 17 +++++----- .../const-param-type-depends-on-type-param.rs | 11 ++++--- ...st-param-type-depends-on-type-param.stderr | 18 +++++++---- .../ui/const-generics/issues/issue-71381.rs | 2 ++ .../const-generics/issues/issue-71381.stderr | 16 ++++++++-- .../ui/const-generics/issues/issue-71611.rs | 1 + .../const-generics/issues/issue-71611.stderr | 8 ++++- 16 files changed, 160 insertions(+), 29 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0770.md create mode 100644 src/test/ui/const-generics/const-param-type-depends-on-const-param.rs create mode 100644 src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 60aa12b0511c7..6160450d76676 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -452,6 +452,7 @@ E0766: include_str!("./error_codes/E0766.md"), E0767: include_str!("./error_codes/E0767.md"), E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), +E0770: include_str!("./error_codes/E0770.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0671.md b/src/librustc_error_codes/error_codes/E0671.md index 449fb8ffc8945..a993ce826a737 100644 --- a/src/librustc_error_codes/error_codes/E0671.md +++ b/src/librustc_error_codes/error_codes/E0671.md @@ -3,7 +3,7 @@ Const parameters cannot depend on type parameters. The following is therefore invalid: -```compile_fail,E0741 +```compile_fail,E0770 #![feature(const_generics)] fn const_id() -> T { // error diff --git a/src/librustc_error_codes/error_codes/E0770.md b/src/librustc_error_codes/error_codes/E0770.md new file mode 100644 index 0000000000000..278bf9b907b24 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0770.md @@ -0,0 +1,15 @@ +The type of a const parameter references other generic parameters. + +Erroneous code example: + +```compile_fail,E0770 +#![feature(const_generics)] +fn foo() {} // error! +``` + +To fix this error, use a concrete type for the const parameter: + +``` +#![feature(const_generics)] +fn foo() {} +``` diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 4f25b948eb66e..c5ac7f7413ad4 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -442,6 +442,16 @@ impl<'a> Resolver<'a> { ); err } + ResolutionError::ParamInTyOfConstArg => { + let mut err = struct_span_err!( + self.session, + span, + E0770, + "the type of const parameters must not depend on other generic parameters" + ); + err.span_label(span, "const parameters must have a concrete type"); + err + } ResolutionError::SelfInTyParamDefault => { let mut err = struct_span_err!( self.session, diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index c165a601408fd..b252e5f29a3e5 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -123,6 +123,10 @@ crate enum RibKind<'a> { /// from the default of a type parameter because they're not declared /// before said type parameter. Also see the `visit_generics` override. ForwardTyParamBanRibKind, + + /// We are inside of the type of a const parameter. Can't refer to any + /// parameters. + ConstParamTyRibKind, } impl RibKind<'_> { @@ -135,7 +139,8 @@ impl RibKind<'_> { | FnItemRibKind | ConstantItemRibKind | ModuleRibKind(_) - | MacroDefinition(_) => false, + | MacroDefinition(_) + | ConstParamTyRibKind => false, AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true, } } @@ -562,7 +567,11 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { for bound in ¶m.bounds { self.visit_param_bound(bound); } + self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind)); + self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind)); self.visit_ty(ty); + self.ribs[TypeNS].pop().unwrap(); + self.ribs[ValueNS].pop().unwrap(); } } } @@ -798,7 +807,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ItemRibKind(..) | ConstantItemRibKind | ModuleRibKind(..) - | ForwardTyParamBanRibKind => { + | ForwardTyParamBanRibKind + | ConstParamTyRibKind => { return false; } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a265c15c18bc9..ba365e8f8418c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -214,6 +214,8 @@ enum ResolutionError<'a> { BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>), /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) + /// ERROR E0770: the type of const parameters must not depend on other generic parameters. + ParamInTyOfConstArg, /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label @@ -2480,6 +2482,12 @@ impl<'a> Resolver<'a> { } return Res::Err; } + ConstParamTyRibKind => { + if record_used { + self.report_error(span, ParamInTyOfConstArg); + } + return Res::Err; + } } } if let Some(res_err) = res_err { @@ -2503,6 +2511,12 @@ impl<'a> Resolver<'a> { // This was an attempt to use a type parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params, FnItemRibKind => HasGenericParams::Yes, + ConstParamTyRibKind => { + if record_used { + self.report_error(span, ResolutionError::ParamInTyOfConstArg); + } + return Res::Err; + } }; if record_used { @@ -2527,9 +2541,21 @@ impl<'a> Resolver<'a> { } for rib in ribs { let has_generic_params = match rib.kind { + NormalRibKind + | ClosureOrAsyncRibKind + | AssocItemRibKind + | ModuleRibKind(..) + | MacroDefinition(..) + | ForwardTyParamBanRibKind + | ConstantItemRibKind => continue, ItemRibKind(has_generic_params) => has_generic_params, FnItemRibKind => HasGenericParams::Yes, - _ => continue, + ConstParamTyRibKind => { + if record_used { + self.report_error(span, ResolutionError::ParamInTyOfConstArg); + } + return Res::Err; + } }; // This was an attempt to use a const parameter outside its scope. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs new file mode 100644 index 0000000000000..6eb13c38e021c --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs @@ -0,0 +1,13 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +// Currently, const parameters cannot depend on other generic parameters, +// as our current implementation can't really support this. +// +// We may want to lift this restriction in the future. + +pub struct Dependent([(); N]); +//~^ ERROR: the type of const parameters must not depend on other generic parameters +//~| ERROR: cycle detected when computing type of `Dependent::X` + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr new file mode 100644 index 0000000000000..63416732bf4ce --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -0,0 +1,31 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-const-param.rs:9:52 + | +LL | pub struct Dependent([(); N]); + | ^ const parameters must have a concrete type + +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/const-param-type-depends-on-const-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error[E0391]: cycle detected when computing type of `Dependent::X` + --> $DIR/const-param-type-depends-on-const-param.rs:9:44 + | +LL | pub struct Dependent([(); N]); + | ^ + | + = note: ...which again requires computing type of `Dependent::X`, completing the cycle +note: cycle used when computing type of `Dependent` + --> $DIR/const-param-type-depends-on-const-param.rs:9:1 + | +LL | pub struct Dependent([(); N]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs index 86ab8075896aa..db15ececfa436 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; struct B(PhantomData<[T; N]>); //~ ERROR const generics are unstable -//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]` +//~^ ERROR the type of const parameters must not depend on other generic parameters fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index 92a7edf96bccb..a2182d9edaf3d 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -1,3 +1,9 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 + | +LL | struct B(PhantomData<[T; N]>); + | ^ const parameters must have a concrete type + error[E0658]: const generics are unstable --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19 | @@ -7,15 +13,6 @@ LL | struct B(PhantomData<[T; N]>); = note: see issue #44580 for more information = help: add `#![feature(const_generics)]` to the crate attributes to enable -error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter - --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 - | -LL | struct B(PhantomData<[T; N]>); - | ^ `T` may not derive both `PartialEq` and `Eq` - | - = note: it is not currently possible to use a type parameter as the type of a const parameter - error: aborting due to 2 previous errors -Some errors have detailed explanations: E0658, E0741. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs index 654e36df37e98..7fe04a43412a1 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -1,12 +1,13 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete -// Currently, const parameters cannot depend on type parameters, because there is no way to -// enforce the structural-match property on an arbitrary type parameter. This restriction -// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more -// details. +// Currently, const parameters cannot depend on other generic parameters, +// as our current implementation can't really support this. +// +// We may want to lift this restriction in the future. pub struct Dependent([(); X]); -//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]` +//~^ ERROR: the type of const parameters must not depend on other generic parameters +//~| ERROR: parameter `T` is never used fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index ed05264161e53..606bb4f4fe7e0 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -1,3 +1,9 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-type-param.rs:9:34 + | +LL | pub struct Dependent([(); X]); + | ^ const parameters must have a concrete type + warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/const-param-type-depends-on-type-param.rs:1:12 | @@ -7,14 +13,14 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter - --> $DIR/const-param-type-depends-on-type-param.rs:9:34 +error[E0392]: parameter `T` is never used + --> $DIR/const-param-type-depends-on-type-param.rs:9:22 | LL | pub struct Dependent([(); X]); - | ^ `T` may not derive both `PartialEq` and `Eq` + | ^ unused parameter | - = note: it is not currently possible to use a type parameter as the type of a const parameter + = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` -error: aborting due to previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0741`. +For more information about this error, try `rustc --explain E0392`. diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs index c32bd2847f837..08f9482394218 100644 --- a/src/test/ui/const-generics/issues/issue-71381.rs +++ b/src/test/ui/const-generics/issues/issue-71381.rs @@ -12,6 +12,7 @@ unsafe extern "C" fn pass(args: PassArg) { impl Test { pub fn call_me(&self) { //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters self.0 = Self::trampiline:: as _ } @@ -20,6 +21,7 @@ impl Test { const IDX: usize, const FN: unsafe extern "C" fn(Args), //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters >( args: Args, ) { diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr index 6bb776fcfc017..177a2cdf14c32 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.stderr @@ -1,3 +1,15 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:13:82 + | +LL | pub fn call_me(&self) { + | ^^^^ const parameters must have a concrete type + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:22:40 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^ const parameters must have a concrete type + error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71381.rs:13:61 | @@ -5,10 +17,10 @@ LL | pub fn call_me $DIR/issue-71381.rs:21:19 + --> $DIR/issue-71381.rs:22:19 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs index 64a049e743faf..06ff38dec66c7 100644 --- a/src/test/ui/const-generics/issues/issue-71611.rs +++ b/src/test/ui/const-generics/issues/issue-71611.rs @@ -3,6 +3,7 @@ fn func(outer: A) { //~^ ERROR: using function pointers as const generic parameters is forbidden + //~| ERROR: the type of const parameters must not depend on other generic parameters F(outer); } diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr index 9a7bf1c0a8841..fe8978b42988e 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.stderr @@ -1,8 +1,14 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71611.rs:4:31 + | +LL | fn func(outer: A) { + | ^ const parameters must have a concrete type + error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71611.rs:4:21 | LL | fn func(outer: A) { | ^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors From 14a1031ec6cc4c8a0475e92a4c6ddcd75108e0ee Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 8 Jul 2020 22:25:22 +0200 Subject: [PATCH 39/69] add self dependent const param test --- ...const-param-type-depends-on-const-param.rs | 4 ++++ ...t-param-type-depends-on-const-param.stderr | 21 ++++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs index 6eb13c38e021c..9aae73ca4b098 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs @@ -10,4 +10,8 @@ pub struct Dependent([(); N]); //~^ ERROR: the type of const parameters must not depend on other generic parameters //~| ERROR: cycle detected when computing type of `Dependent::X` +pub struct SelfDependent; +//~^ ERROR: the type of const parameters must not depend on other generic parameters +//~| ERROR: cycle detected when computing type of `SelfDependent::N` + fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr index 63416732bf4ce..22e55975dcdd8 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -4,6 +4,12 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | pub struct Dependent([(); N]); | ^ const parameters must have a concrete type +error[E0769]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-const-param.rs:13:40 + | +LL | pub struct SelfDependent; + | ^ const parameters must have a concrete type + warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/const-param-type-depends-on-const-param.rs:1:12 | @@ -26,6 +32,19 @@ note: cycle used when computing type of `Dependent` LL | pub struct Dependent([(); N]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 1 warning emitted +error[E0391]: cycle detected when computing type of `SelfDependent::N` + --> $DIR/const-param-type-depends-on-const-param.rs:13:32 + | +LL | pub struct SelfDependent; + | ^ + | + = note: ...which again requires computing type of `SelfDependent::N`, completing the cycle +note: cycle used when computing type of `SelfDependent` + --> $DIR/const-param-type-depends-on-const-param.rs:13:1 + | +LL | pub struct SelfDependent; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0391`. From 3f558402431f4ce033fb472bdd9cc10bd92fa73a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 9 Jul 2020 22:18:22 +0200 Subject: [PATCH 40/69] relax Node lt bounds --- src/librustc_hir/hir.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 07b489a756267..9204f778a24b9 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2687,7 +2687,7 @@ pub enum Node<'hir> { Crate(&'hir CrateItem<'hir>), } -impl Node<'_> { +impl<'hir> Node<'hir> { pub fn ident(&self) -> Option { match self { Node::TraitItem(TraitItem { ident, .. }) @@ -2698,7 +2698,7 @@ impl Node<'_> { } } - pub fn fn_decl(&self) -> Option<&FnDecl<'_>> { + pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> { match self { Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. }) | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) @@ -2722,7 +2722,7 @@ impl Node<'_> { } } - pub fn generics(&self) -> Option<&Generics<'_>> { + pub fn generics(&self) -> Option<&'hir Generics<'hir>> { match self { Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), From 6f5d8bf5c8ec9a62d62623e59fceb8abd0996f1b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 9 Jul 2020 22:26:49 +0200 Subject: [PATCH 41/69] don't supply generics to AnonConsts in param lists --- src/librustc_typeck/collect.rs | 61 +++++++++++++++++-- ...const-param-type-depends-on-const-param.rs | 2 - ...t-param-type-depends-on-const-param.stderr | 33 +--------- .../ui/const-generics/issues/issue-74101.rs | 9 +++ 4 files changed, 68 insertions(+), 37 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-74101.rs diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4354996614b2a..17212187e6a01 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::weak_lang_items; -use rustc_hir::{GenericParamKind, Node}; +use rustc_hir::{GenericParamKind, HirId, Node}; use rustc_middle::hir::map::blocks::FnLikeNode; use rustc_middle::hir::map::Map; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -1155,6 +1155,35 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option Visitor<'v> for AnonConstInParamListDetector { + type Map = intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { + let prev = self.in_param_list; + self.in_param_list = true; + intravisit::walk_generic_param(self, p); + self.in_param_list = prev; + } + + fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { + if self.in_param_list && self.ct == c.hir_id { + self.found_anon_const_in_list = true; + } else { + intravisit::walk_anon_const(self, c) + } + } +} + fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { use rustc_hir::*; @@ -1176,10 +1205,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { let parent_id = tcx.hir().get_parent_item(hir_id); let parent_def_id = tcx.hir().local_def_id(parent_id); - // HACK(eddyb) this provides the correct generics when - // `feature(const_generics)` is enabled, so that const expressions - // used with const generics, e.g. `Foo<{N+1}>`, can work at all. - if tcx.lazy_normalization() { + let mut in_param_list = false; + for (_parent, node) in tcx.hir().parent_iter(hir_id) { + if let Some(generics) = node.generics() { + let mut visitor = AnonConstInParamListDetector { + in_param_list: false, + found_anon_const_in_list: false, + ct: hir_id, + }; + + visitor.visit_generics(generics); + in_param_list = visitor.found_anon_const_in_list; + break; + } + } + + if in_param_list { + // We do not allow generic parameters in anon consts if we are inside + // of a param list. + // + // This affects both default type bindings, e.g. `struct()]>(T, U)`, + // and the types of const parameters, e.g. `struct V();`. + None + } else if tcx.lazy_normalization() { + // HACK(eddyb) this provides the correct generics when + // `feature(const_generics)` is enabled, so that const expressions + // used with const generics, e.g. `Foo<{N+1}>`, can work at all. Some(parent_def_id.to_def_id()) } else { let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id)); diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs index 9aae73ca4b098..5aa3617d1d7e0 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs @@ -8,10 +8,8 @@ pub struct Dependent([(); N]); //~^ ERROR: the type of const parameters must not depend on other generic parameters -//~| ERROR: cycle detected when computing type of `Dependent::X` pub struct SelfDependent; //~^ ERROR: the type of const parameters must not depend on other generic parameters -//~| ERROR: cycle detected when computing type of `SelfDependent::N` fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr index 22e55975dcdd8..a06bdea1b3ca0 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -4,8 +4,8 @@ error[E0770]: the type of const parameters must not depend on other generic para LL | pub struct Dependent([(); N]); | ^ const parameters must have a concrete type -error[E0769]: the type of const parameters must not depend on other generic parameters - --> $DIR/const-param-type-depends-on-const-param.rs:13:40 +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/const-param-type-depends-on-const-param.rs:12:40 | LL | pub struct SelfDependent; | ^ const parameters must have a concrete type @@ -19,32 +19,5 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0391]: cycle detected when computing type of `Dependent::X` - --> $DIR/const-param-type-depends-on-const-param.rs:9:44 - | -LL | pub struct Dependent([(); N]); - | ^ - | - = note: ...which again requires computing type of `Dependent::X`, completing the cycle -note: cycle used when computing type of `Dependent` - --> $DIR/const-param-type-depends-on-const-param.rs:9:1 - | -LL | pub struct Dependent([(); N]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0391]: cycle detected when computing type of `SelfDependent::N` - --> $DIR/const-param-type-depends-on-const-param.rs:13:32 - | -LL | pub struct SelfDependent; - | ^ - | - = note: ...which again requires computing type of `SelfDependent::N`, completing the cycle -note: cycle used when computing type of `SelfDependent` - --> $DIR/const-param-type-depends-on-const-param.rs:13:1 - | -LL | pub struct SelfDependent; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/const-generics/issues/issue-74101.rs b/src/test/ui/const-generics/issues/issue-74101.rs new file mode 100644 index 0000000000000..2f427ef3a27dc --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74101.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn test() {} + +struct Foo; + +fn main() {} From 0c511ab5c7fae69635ea4f296a1ffae25a22b0f0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 11:10:22 +0200 Subject: [PATCH 42/69] update help message --- src/librustc_resolve/diagnostics.rs | 7 +++++-- src/librustc_resolve/lib.rs | 14 ++++++++++---- .../const-param-type-depends-on-const-param.stderr | 4 ++-- ...param-type-depends-on-type-param-ungated.stderr | 2 +- .../const-param-type-depends-on-type-param.stderr | 2 +- .../ui/const-generics/issues/issue-71381.stderr | 4 ++-- .../ui/const-generics/issues/issue-71611.stderr | 2 +- 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index c5ac7f7413ad4..575049c6bac2f 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -442,14 +442,17 @@ impl<'a> Resolver<'a> { ); err } - ResolutionError::ParamInTyOfConstArg => { + ResolutionError::ParamInTyOfConstArg(name) => { let mut err = struct_span_err!( self.session, span, E0770, "the type of const parameters must not depend on other generic parameters" ); - err.span_label(span, "const parameters must have a concrete type"); + err.span_label( + span, + format!("the type must not depend on the parameter `{}`", name), + ); err } ResolutionError::SelfInTyParamDefault => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ba365e8f8418c..c3686ca4899bc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -215,7 +215,7 @@ enum ResolutionError<'a> { /// Error E0128: type parameters with a default cannot use forward-declared identifiers. ForwardDeclaredTyParam, // FIXME(const_generics:defaults) /// ERROR E0770: the type of const parameters must not depend on other generic parameters. - ParamInTyOfConstArg, + ParamInTyOfConstArg(Symbol), /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label @@ -2484,7 +2484,7 @@ impl<'a> Resolver<'a> { } ConstParamTyRibKind => { if record_used { - self.report_error(span, ParamInTyOfConstArg); + self.report_error(span, ParamInTyOfConstArg(rib_ident.name)); } return Res::Err; } @@ -2513,7 +2513,10 @@ impl<'a> Resolver<'a> { FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if record_used { - self.report_error(span, ResolutionError::ParamInTyOfConstArg); + self.report_error( + span, + ResolutionError::ParamInTyOfConstArg(rib_ident.name), + ); } return Res::Err; } @@ -2552,7 +2555,10 @@ impl<'a> Resolver<'a> { FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if record_used { - self.report_error(span, ResolutionError::ParamInTyOfConstArg); + self.report_error( + span, + ResolutionError::ParamInTyOfConstArg(rib_ident.name), + ); } return Res::Err; } diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr index a06bdea1b3ca0..ece31b5fab200 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -2,13 +2,13 @@ error[E0770]: the type of const parameters must not depend on other generic para --> $DIR/const-param-type-depends-on-const-param.rs:9:52 | LL | pub struct Dependent([(); N]); - | ^ const parameters must have a concrete type + | ^ the type must not depend on the parameter `N` error[E0770]: the type of const parameters must not depend on other generic parameters --> $DIR/const-param-type-depends-on-const-param.rs:12:40 | LL | pub struct SelfDependent; - | ^ const parameters must have a concrete type + | ^ the type must not depend on the parameter `N` warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/const-param-type-depends-on-const-param.rs:1:12 diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index a2182d9edaf3d..7a2ee689c3318 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -2,7 +2,7 @@ error[E0770]: the type of const parameters must not depend on other generic para --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22 | LL | struct B(PhantomData<[T; N]>); - | ^ const parameters must have a concrete type + | ^ the type must not depend on the parameter `T` error[E0658]: const generics are unstable --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19 diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index 606bb4f4fe7e0..fa566b5536fee 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -2,7 +2,7 @@ error[E0770]: the type of const parameters must not depend on other generic para --> $DIR/const-param-type-depends-on-type-param.rs:9:34 | LL | pub struct Dependent([(); X]); - | ^ const parameters must have a concrete type + | ^ the type must not depend on the parameter `T` warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/const-param-type-depends-on-type-param.rs:1:12 diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr index 177a2cdf14c32..fe6d5125223dc 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.stderr @@ -2,13 +2,13 @@ error[E0770]: the type of const parameters must not depend on other generic para --> $DIR/issue-71381.rs:13:82 | LL | pub fn call_me(&self) { - | ^^^^ const parameters must have a concrete type + | ^^^^ the type must not depend on the parameter `Args` error[E0770]: the type of const parameters must not depend on other generic parameters --> $DIR/issue-71381.rs:22:40 | LL | const FN: unsafe extern "C" fn(Args), - | ^^^^ const parameters must have a concrete type + | ^^^^ the type must not depend on the parameter `Args` error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71381.rs:13:61 diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr index fe8978b42988e..a8363cdff78d5 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.stderr @@ -2,7 +2,7 @@ error[E0770]: the type of const parameters must not depend on other generic para --> $DIR/issue-71611.rs:4:31 | LL | fn func(outer: A) { - | ^ const parameters must have a concrete type + | ^ the type must not depend on the parameter `A` error: using function pointers as const generic parameters is forbidden --> $DIR/issue-71611.rs:4:21 From 01f5dd374cb1762d722ed3537779377a74774cf1 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 11:40:26 +0200 Subject: [PATCH 43/69] bless ui tests --- .../const-param-type-depends-on-const-param.stderr | 1 + .../const-param-type-depends-on-type-param-ungated.stderr | 3 ++- .../const-param-type-depends-on-type-param.stderr | 3 ++- src/test/ui/const-generics/issues/issue-71381.stderr | 1 + src/test/ui/const-generics/issues/issue-71611.stderr | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr index ece31b5fab200..f6606aea726ad 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -21,3 +21,4 @@ LL | #![feature(const_generics)] error: aborting due to 2 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index 7a2ee689c3318..35996e833610d 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -15,4 +15,5 @@ LL | struct B(PhantomData<[T; N]>); error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0658, E0770. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index fa566b5536fee..d081dcbbc7a4e 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -23,4 +23,5 @@ LL | pub struct Dependent([(); X]); error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0392`. +Some errors have detailed explanations: E0392, E0770. +For more information about an error, try `rustc --explain E0392`. diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr index fe6d5125223dc..fd4ebe3dead81 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.stderr @@ -24,3 +24,4 @@ LL | const FN: unsafe extern "C" fn(Args), error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr index a8363cdff78d5..e2c9f22361ebe 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.stderr @@ -12,3 +12,4 @@ LL | fn func(outer: A) { error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0770`. From e009b53df4d9b0c2604c0e8ede02c0104bbd5548 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 11:46:39 +0200 Subject: [PATCH 44/69] add regression tests for #67144 --- .../type-dependent/issue-67144-1.rs | 28 +++++++++++++++++++ .../type-dependent/issue-67144-2.rs | 22 +++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/test/ui/const-generics/type-dependent/issue-67144-1.rs create mode 100644 src/test/ui/const-generics/type-dependent/issue-67144-2.rs diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-1.rs b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs new file mode 100644 index 0000000000000..a3d059591987c --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs @@ -0,0 +1,28 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct X; + +impl X { + pub fn getn(&self) -> [u8; N] { + getn::() + } +} + +fn getn() -> [u8; N] { + unsafe { + std::mem::zeroed() + } +} + +fn main() { + // works + let [a,b,c] = getn::<3>(); + + // cannot pattern-match on an array without a fixed length + let [a,b,c] = X.getn::<3>(); + + // mismatched types, expected array `[u8; 3]` found array `[u8; _]` + let arr: [u8; 3] = X.getn::<3>(); +} diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-2.rs b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs new file mode 100644 index 0000000000000..c53a149fa8d46 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs @@ -0,0 +1,22 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct A; + +struct X; + +impl X { + fn inner() -> A { + outer::() + } +} + +fn outer() -> A { + A +} + +fn main() { + let i: A<3usize> = outer::<3usize>(); + let o: A<3usize> = X::inner::<3usize>(); +} From 333dce960ccf826cc22a4f922328aa14f0a25bbe Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 11:54:20 +0200 Subject: [PATCH 45/69] add regression test for #68596 --- .../ui/const-generics/issues/issue-68596.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-68596.rs diff --git a/src/test/ui/const-generics/issues/issue-68596.rs b/src/test/ui/const-generics/issues/issue-68596.rs new file mode 100644 index 0000000000000..1f96e7d3b410a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68596.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +pub struct S(u8); + +impl S { + pub fn get(&self) -> &u8 { + &self.0 + } +} + +fn main() { + const A: u8 = 5; + let s = S(0); + + s.get::(); +} From 137ca05ccd2ef6f0bb5583f943f4395272a170c9 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:03:00 +0200 Subject: [PATCH 46/69] add regression test for #70217 --- .../const-generics/type-dependent/issue-70217.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/ui/const-generics/type-dependent/issue-70217.rs diff --git a/src/test/ui/const-generics/type-dependent/issue-70217.rs b/src/test/ui/const-generics/type-dependent/issue-70217.rs new file mode 100644 index 0000000000000..caa611cbd797f --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-70217.rs @@ -0,0 +1,16 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Struct; + +impl Struct { + fn method(&self) {} +} + +fn test(x: Struct) { + Struct::::method::(&x); + x.method::(); +} + +fn main() {} From eee160cdea88da87396f5682220193a01ff177b0 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:10:15 +0200 Subject: [PATCH 47/69] add regression test for #70586 --- .../type-dependent/issue-70586.rs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/test/ui/const-generics/type-dependent/issue-70586.rs diff --git a/src/test/ui/const-generics/type-dependent/issue-70586.rs b/src/test/ui/const-generics/type-dependent/issue-70586.rs new file mode 100644 index 0000000000000..5a0888506eb1e --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-70586.rs @@ -0,0 +1,33 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +use std::marker::PhantomData; + +// This namespace is necessary for the ICE to trigger +struct Namespace; + +impl Namespace { + pub fn const_chunks_exact() -> ConstChunksExact<'static, T, N> { + ConstChunksExact { inner: PhantomData } + } +} + + +#[derive(Debug)] +pub struct ConstChunksExact<'a, T, const N: usize> { + inner: PhantomData<&'a T> +} + +impl <'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, { N }> { + type Item = &'a [T; N]; + + fn next(&mut self) -> Option { + unreachable!() + } +} + +fn main() { + let mut chunks = Namespace::const_chunks_exact::(); + let _next: &[i32; 3] = chunks.next().unwrap(); +} From f52039d5e82df9bf8cfbe7ed1ec337c3e426acee Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:14:03 +0200 Subject: [PATCH 48/69] add regression test for #71169 --- .../ui/const-generics/issues/issue-71169.rs | 10 ++++++++++ .../ui/const-generics/issues/issue-71169.stderr | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-71169.rs create mode 100644 src/test/ui/const-generics/issues/issue-71169.stderr diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs new file mode 100644 index 0000000000000..943a16cfcd6a7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn foo() {} +//~^ ERROR the type of const parameters must not +fn main() { + const DATA: [u8; 4] = *b"ABCD"; + foo::<4, DATA>(); + //~^ ERROR constant expression depends on +} diff --git a/src/test/ui/const-generics/issues/issue-71169.stderr b/src/test/ui/const-generics/issues/issue-71169.stderr new file mode 100644 index 0000000000000..6d4cf4027c146 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.stderr @@ -0,0 +1,17 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71169.rs:4:43 + | +LL | fn foo() {} + | ^^^ the type must not depend on the parameter `LEN` + +error: constant expression depends on a generic parameter + --> $DIR/issue-71169.rs:8:14 + | +LL | foo::<4, DATA>(); + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. From a2b18274a890eb19db5f784b2fb6925eebcdf86f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:17:27 +0200 Subject: [PATCH 49/69] add regression test for #71348 --- .../type-dependent/issue-71348.rs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/test/ui/const-generics/type-dependent/issue-71348.rs diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.rs b/src/test/ui/const-generics/type-dependent/issue-71348.rs new file mode 100644 index 0000000000000..ec22dcdf60b46 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71348.rs @@ -0,0 +1,35 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Foo { + i: i32, +} + +trait Get<'a, const N: &'static str> { + type Target: 'a; + + fn get(&'a self) -> &'a Self::Target; +} + +impl Foo { + fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + where + Self: Get<'a, N>, + { + self.get() + } +} + +impl<'a> Get<'a, "int"> for Foo { + type Target = i32; + + fn get(&'a self) -> &'a Self::Target { + &self.i + } +} + +fn main() { + let foo = Foo { i: 123 }; + assert_eq!(foo.ask::<"int">(), &123); +} From de8d2e897f8397d1005a3a35c2eb5a710d5f1e32 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:23:38 +0200 Subject: [PATCH 50/69] add regression test for #71805 --- .../type-dependent/issue-71805.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/test/ui/const-generics/type-dependent/issue-71805.rs diff --git a/src/test/ui/const-generics/type-dependent/issue-71805.rs b/src/test/ui/const-generics/type-dependent/issue-71805.rs new file mode 100644 index 0000000000000..6823d780aefa9 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71805.rs @@ -0,0 +1,41 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +use std::mem::MaybeUninit; + +trait CollectSlice<'a>: Iterator { + fn inner_array(&mut self) -> [Self::Item; N]; + + fn collect_array(&mut self) -> [Self::Item; N] { + let result = self.inner_array(); + assert!(self.next().is_none()); + result + } +} + +impl<'a, I: ?Sized> CollectSlice<'a> for I +where + I: Iterator, +{ + fn inner_array(&mut self) -> [Self::Item; N] { + let mut result: [MaybeUninit; N] = + unsafe { MaybeUninit::uninit().assume_init() }; + + let mut count = 0; + for (dest, item) in result.iter_mut().zip(self) { + *dest = MaybeUninit::new(item); + count += 1; + } + + assert_eq!(N, count); + + let temp_ptr: *const [MaybeUninit; N] = &result; + unsafe { std::ptr::read(temp_ptr as *const [Self::Item; N]) } + } +} + +fn main() { + let mut foos = [0u64; 9].iter().cloned(); + let _bar: [u64; 9] = foos.collect_array::<9_usize>(); +} From 946cb11a1ebeabb5b170e58c87787a24693251e9 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:32:43 +0200 Subject: [PATCH 51/69] add regression test for #73120 --- .../issues/auxiliary/const_generic_issues_lib.rs | 14 ++++++++++++++ src/test/ui/const-generics/issues/issue-73120.rs | 8 ++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs create mode 100644 src/test/ui/const-generics/issues/issue-73120.rs diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs new file mode 100644 index 0000000000000..59a4d345cbccb --- /dev/null +++ b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs @@ -0,0 +1,14 @@ +#![feature(const_generics)] + +// All of these three items must be in `lib2` to reproduce the error + +pub trait TypeFn { + type Output; +} + +pub struct GenericType; + +// Removing the braces around `42` resolves the crash +impl TypeFn for GenericType<{ 42 }> { + type Output = (); +} diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs new file mode 100644 index 0000000000000..aea4de39f79ce --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73120.rs @@ -0,0 +1,8 @@ +// check-pass +// aux-build:const_generic_issues_lib.rs +extern crate const_generic_issues_lib as lib2; +fn unused_function( + _: as lib2::TypeFn>::Output +) {} + +fn main() {} From 09ba0bda2caa448d381b952d2b52df1782c44966 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:35:23 +0200 Subject: [PATCH 52/69] add regression test for #73491 --- src/test/ui/const-generics/issues/issue-73491.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-73491.rs diff --git a/src/test/ui/const-generics/issues/issue-73491.rs b/src/test/ui/const-generics/issues/issue-73491.rs new file mode 100644 index 0000000000000..05e1513bb75df --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73491.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +const LEN: usize = 1024; + +fn hoge() {} + +fn main() {} From e23095011f8f0a6ea146e10821b95bcfb1807b8c Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:39:02 +0200 Subject: [PATCH 53/69] add regression test for #73508 --- .../ui/const-generics/issues/issue-73508.rs | 6 ++++++ .../ui/const-generics/issues/issue-73508.stderr | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-73508.rs create mode 100644 src/test/ui/const-generics/issues/issue-73508.stderr diff --git a/src/test/ui/const-generics/issues/issue-73508.rs b/src/test/ui/const-generics/issues/issue-73508.rs new file mode 100644 index 0000000000000..ba2e2a38e7470 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.rs @@ -0,0 +1,6 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +pub const fn func_name() {} +//~^ ERROR using raw pointers + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-73508.stderr b/src/test/ui/const-generics/issues/issue-73508.stderr new file mode 100644 index 0000000000000..23ad1818b6f37 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-73508.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: using raw pointers as const generic parameters is forbidden + --> $DIR/issue-73508.rs:3:33 + | +LL | pub const fn func_name() {} + | ^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + From d187e8108b93a40d6c22f919297a73cbd9901735 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:43:33 +0200 Subject: [PATCH 54/69] add regression test for #73730 --- .../type-dependent/issue-73730.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/test/ui/const-generics/type-dependent/issue-73730.rs diff --git a/src/test/ui/const-generics/type-dependent/issue-73730.rs b/src/test/ui/const-generics/type-dependent/issue-73730.rs new file mode 100644 index 0000000000000..d90cc50ddc447 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-73730.rs @@ -0,0 +1,17 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Foo<'a, A>: Iterator { + fn bar(&mut self) -> *const [A; N]; +} + +impl<'a, A, I: ?Sized> Foo<'a, A> for I where I: Iterator { + fn bar(&mut self) -> *const [A; N] { + std::ptr::null() + } +} + +fn main() { + (0_u8 .. 10).bar::<10_usize>(); +} From 8faeb0e797947df535b1120b5da850fd9c765b3a Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 16 Jul 2020 12:46:02 +0200 Subject: [PATCH 55/69] add regression test for #74255 --- .../ui/const-generics/issues/issue-74255.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/test/ui/const-generics/issues/issue-74255.rs diff --git a/src/test/ui/const-generics/issues/issue-74255.rs b/src/test/ui/const-generics/issues/issue-74255.rs new file mode 100644 index 0000000000000..55ccf57dc99c3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74255.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_generics)] +#![allow(dead_code, incomplete_features)] + +#[derive(PartialEq, Eq)] +enum IceEnum { + Variant +} + +struct IceStruct; + +impl IceStruct { + fn ice_struct_fn() {} +} + +fn main() { + IceStruct::ice_struct_fn::<{IceEnum::Variant}>(); +} From ca253cab3689c0d525dabda10e35c469839b2c4b Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 13 Jul 2020 16:51:37 +0200 Subject: [PATCH 56/69] Clean up or comment every unwrap in BTreeMap's main code. --- src/liballoc/collections/btree/map.rs | 81 +++++++++++--------------- src/liballoc/collections/btree/node.rs | 5 ++ 2 files changed, 40 insertions(+), 46 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index f3781db1cf784..d94c9539e6dc5 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -151,7 +151,7 @@ impl Clone for BTreeMap { let mut out_tree = BTreeMap { root: Some(node::Root::new_leaf()), length: 0 }; { - let root = out_tree.root.as_mut().unwrap(); + let root = out_tree.root.as_mut().unwrap(); // unwrap succeeds because we just wrapped let mut out_node = match root.as_mut().force() { Leaf(leaf) => leaf, Internal(_) => unreachable!(), @@ -171,14 +171,10 @@ impl Clone for BTreeMap { } Internal(internal) => { let mut out_tree = clone_subtree(internal.first_edge().descend()); - out_tree.ensure_root_is_owned(); { - // Ideally we'd use the return of ensure_root_is_owned - // instead of re-unwrapping here but unfortunately that - // borrows all of out_tree and we need access to the - // length below. - let mut out_node = out_tree.root.as_mut().unwrap().push_level(); + let out_root = BTreeMap::ensure_is_owned(&mut out_tree.root); + let mut out_node = out_root.push_level(); let mut in_edge = internal.first_edge(); while let Ok(kv) = in_edge.right_kv() { let (k, v) = kv.into_kv(); @@ -212,7 +208,7 @@ impl Clone for BTreeMap { // Ord` constraint, which this method lacks. BTreeMap { root: None, length: 0 } } else { - clone_subtree(self.root.as_ref().unwrap().as_ref()) + clone_subtree(self.root.as_ref().unwrap().as_ref()) // unwrap succeeds because not empty } } } @@ -243,8 +239,8 @@ where } fn replace(&mut self, key: K) -> Option { - self.ensure_root_is_owned(); - match search::search_tree::, K, (), K>(self.root.as_mut()?.as_mut(), &key) { + let root = Self::ensure_is_owned(&mut self.root); + match search::search_tree::, K, (), K>(root.as_mut(), &key) { Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)), GoDown(handle) => { VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData } @@ -943,7 +939,6 @@ impl BTreeMap { // Second, we build a tree from the sorted sequence in linear time. self.from_sorted_iter(iter); - self.fix_right_edge(); } /// Constructs a double-ended iterator over a sub-range of elements in the map. @@ -1058,8 +1053,8 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { // FIXME(@porglezomp) Avoid allocating if we don't insert - self.ensure_root_is_owned(); - match search::search_tree(self.root.as_mut().unwrap().as_mut(), &key) { + let root = Self::ensure_is_owned(&mut self.root); + match search::search_tree(root.as_mut(), &key) { Found(handle) => { Occupied(OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData }) } @@ -1070,8 +1065,8 @@ impl BTreeMap { } fn from_sorted_iter>(&mut self, iter: I) { - self.ensure_root_is_owned(); - let mut cur_node = self.root.as_mut().unwrap().as_mut().last_leaf_edge().into_node(); + let root = Self::ensure_is_owned(&mut self.root); + let mut cur_node = root.as_mut().last_leaf_edge().into_node(); // Iterate through all key-value pairs, pushing them into nodes at the right level. for (key, value) in iter { // Try to push key-value pair into the current leaf node. @@ -1116,11 +1111,12 @@ impl BTreeMap { self.length += 1; } + Self::fix_right_edge(root) } - fn fix_right_edge(&mut self) { + fn fix_right_edge(root: &mut node::Root) { // Handle underfull nodes, start from the top. - let mut cur_node = self.root.as_mut().unwrap().as_mut(); + let mut cur_node = root.as_mut(); while let Internal(internal) = cur_node.force() { // Check if right-most child is underfull. let mut last_edge = internal.last_edge(); @@ -1179,16 +1175,17 @@ impl BTreeMap { } let total_num = self.len(); + let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty let mut right = Self::new(); - let right_root = right.ensure_root_is_owned(); - for _ in 0..(self.root.as_ref().unwrap().as_ref().height()) { + let right_root = Self::ensure_is_owned(&mut right.root); + for _ in 0..left_root.height() { right_root.push_level(); } { - let mut left_node = self.root.as_mut().unwrap().as_mut(); - let mut right_node = right.root.as_mut().unwrap().as_mut(); + let mut left_node = left_root.as_mut(); + let mut right_node = right_root.as_mut(); loop { let mut split_edge = match search::search_node(left_node, key) { @@ -1214,12 +1211,10 @@ impl BTreeMap { } } - self.fix_right_border(); - right.fix_left_border(); + Self::fix_right_border(left_root); + Self::fix_left_border(right_root); - if self.root.as_ref().unwrap().as_ref().height() - < right.root.as_ref().unwrap().as_ref().height() - { + if left_root.height() < right_root.height() { self.recalc_length(); right.length = total_num - self.len(); } else { @@ -1303,23 +1298,17 @@ impl BTreeMap { } /// Removes empty levels on the top. - fn fix_top(&mut self) { - loop { - { - let node = self.root.as_ref().unwrap().as_ref(); - if node.height() == 0 || node.len() > 0 { - break; - } - } - self.root.as_mut().unwrap().pop_level(); + fn fix_top(root: &mut node::Root) { + while root.height() > 0 && root.as_ref().len() == 0 { + root.pop_level(); } } - fn fix_right_border(&mut self) { - self.fix_top(); + fn fix_right_border(root: &mut node::Root) { + Self::fix_top(root); { - let mut cur_node = self.root.as_mut().unwrap().as_mut(); + let mut cur_node = root.as_mut(); while let Internal(node) = cur_node.force() { let mut last_kv = node.last_kv(); @@ -1337,15 +1326,15 @@ impl BTreeMap { } } - self.fix_top(); + Self::fix_top(root); } /// The symmetric clone of `fix_right_border`. - fn fix_left_border(&mut self) { - self.fix_top(); + fn fix_left_border(root: &mut node::Root) { + Self::fix_top(root); { - let mut cur_node = self.root.as_mut().unwrap().as_mut(); + let mut cur_node = root.as_mut(); while let Internal(node) = cur_node.force() { let mut first_kv = node.first_kv(); @@ -1362,7 +1351,7 @@ impl BTreeMap { } } - self.fix_top(); + Self::fix_top(root); } } @@ -2321,9 +2310,9 @@ impl BTreeMap { } /// If the root node is the empty (non-allocated) root node, allocate our - /// own node. - fn ensure_root_is_owned(&mut self) -> &mut node::Root { - self.root.get_or_insert_with(node::Root::new_leaf) + /// own node. Is an associated function to avoid borrowing the entire BTreeMap. + fn ensure_is_owned(root: &mut Option>) -> &mut node::Root { + root.get_or_insert_with(node::Root::new_leaf) } } diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index ce74d4f8ee688..f7bd64608d63c 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -153,6 +153,11 @@ unsafe impl Sync for Root {} unsafe impl Send for Root {} impl Root { + /// Returns the number of levels below the root. + pub fn height(&self) -> usize { + self.height + } + /// Returns a new owned tree, with its own root node that is initially empty. pub fn new_leaf() -> Self { Root { node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), height: 0 } From b82d332c52dde1680b21c0281f08cc5f30edc082 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Tue, 14 Jul 2020 13:23:15 +0200 Subject: [PATCH 57/69] Separate off BTreeMap support functions and loose their irrelevant bounds --- src/liballoc/collections/btree/map.rs | 120 +++++++++++++------------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index d94c9539e6dc5..bf5748739d470 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1211,8 +1211,8 @@ impl BTreeMap { } } - Self::fix_right_border(left_root); - Self::fix_left_border(right_root); + left_root.fix_right_border(); + right_root.fix_left_border(); if left_root.height() < right_root.height() { self.recalc_length(); @@ -1296,63 +1296,6 @@ impl BTreeMap { self.length = dfs(self.root.as_ref().unwrap().as_ref()); } - - /// Removes empty levels on the top. - fn fix_top(root: &mut node::Root) { - while root.height() > 0 && root.as_ref().len() == 0 { - root.pop_level(); - } - } - - fn fix_right_border(root: &mut node::Root) { - Self::fix_top(root); - - { - let mut cur_node = root.as_mut(); - - while let Internal(node) = cur_node.force() { - let mut last_kv = node.last_kv(); - - if last_kv.can_merge() { - cur_node = last_kv.merge().descend(); - } else { - let right_len = last_kv.reborrow().right_edge().descend().len(); - // `MINLEN + 1` to avoid readjust if merge happens on the next level. - if right_len < node::MIN_LEN + 1 { - last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len); - } - cur_node = last_kv.right_edge().descend(); - } - } - } - - Self::fix_top(root); - } - - /// The symmetric clone of `fix_right_border`. - fn fix_left_border(root: &mut node::Root) { - Self::fix_top(root); - - { - let mut cur_node = root.as_mut(); - - while let Internal(node) = cur_node.force() { - let mut first_kv = node.first_kv(); - - if first_kv.can_merge() { - cur_node = first_kv.merge().descend(); - } else { - let left_len = first_kv.reborrow().left_edge().descend().len(); - if left_len < node::MIN_LEN + 1 { - first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len); - } - cur_node = first_kv.left_edge().descend(); - } - } - } - - Self::fix_top(root); - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2814,6 +2757,65 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter } } +impl node::Root { + /// Removes empty levels on the top, but keep an empty leaf if the entire tree is empty. + fn fix_top(&mut self) { + while self.height() > 0 && self.as_ref().len() == 0 { + self.pop_level(); + } + } + + fn fix_right_border(&mut self) { + self.fix_top(); + + { + let mut cur_node = self.as_mut(); + + while let Internal(node) = cur_node.force() { + let mut last_kv = node.last_kv(); + + if last_kv.can_merge() { + cur_node = last_kv.merge().descend(); + } else { + let right_len = last_kv.reborrow().right_edge().descend().len(); + // `MINLEN + 1` to avoid readjust if merge happens on the next level. + if right_len < node::MIN_LEN + 1 { + last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len); + } + cur_node = last_kv.right_edge().descend(); + } + } + } + + self.fix_top(); + } + + /// The symmetric clone of `fix_right_border`. + fn fix_left_border(&mut self) { + self.fix_top(); + + { + let mut cur_node = self.as_mut(); + + while let Internal(node) = cur_node.force() { + let mut first_kv = node.first_kv(); + + if first_kv.can_merge() { + cur_node = first_kv.merge().descend(); + } else { + let left_len = first_kv.reborrow().left_edge().descend().len(); + if left_len < node::MIN_LEN + 1 { + first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len); + } + cur_node = first_kv.left_edge().descend(); + } + } + } + + self.fix_top(); + } +} + enum UnderflowResult<'a, K, V> { AtRoot, Merged(Handle, K, V, marker::Internal>, marker::Edge>, bool, usize), From 631b2b9b722a3333aa5931fbbfa9df8846d48380 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 16 Jul 2020 09:03:46 -0400 Subject: [PATCH 58/69] Remove unused lazy_static --- Cargo.lock | 1 - src/librustdoc/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 992421dcd7abb..5309c03ee23ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4027,7 +4027,6 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "itertools 0.8.0", - "lazy_static", "minifier", "pulldown-cmark", "rustc-rayon", diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index baceb13cc6141..4af13e4cd587a 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -16,4 +16,3 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tempfile = "3" itertools = "0.8" -lazy_static = "1" From e28c0ea2be3407279ffb1768aa747e9ba8a4fbb6 Mon Sep 17 00:00:00 2001 From: Linda_pp Date: Thu, 16 Jul 2020 23:57:47 +0900 Subject: [PATCH 59/69] Fix typo in the latest release note --- RELEASES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 7bac14cb41534..f36cdee0975a0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -47,7 +47,7 @@ Libraries // Prints "abcdefghijklmnopqrstuvwxyz" ``` - [`OsString` now implements `FromStr`.][71662] -- [The `saturating_neg` method as been added to all signed integer primitive +- [The `saturating_neg` method has been added to all signed integer primitive types, and the `saturating_abs` method has been added for all integer primitive types.][71886] - [`Arc`, `Rc` now implement `From>`, and `Box` now From 52c65e05f53e7a49345bc3041e5656735fdc4f9c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 16 Jul 2020 18:34:49 +0200 Subject: [PATCH 60/69] Remove elements iterator clone and only keep first element instead --- src/librustdoc/html/static/source-script.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index 5c39e760f44d4..6805f2a266f09 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -141,8 +141,8 @@ function createSourceSidebar() { main.insertBefore(sidebar, main.firstChild); // Focus on the current file in the source files sidebar. - var selected_elems = Array.prototype.slice.call(sidebar.getElementsByClassName("selected")); - if (selected_elems.length > 0) { - selected_elems[0].focus(); + var selected_elem = sidebar.getElementsByClassName("selected")[0]; + if (typeof selected_elem !== "undefined") { + selected_elem.focus(); } } From 98450757e5fa18ee0be9213d2830c9363b0f5fd3 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 12:53:44 -0700 Subject: [PATCH 61/69] Revert "Remove "important traits" feature" This reverts commit 1244ced9580b942926afc06815e0691cf3f4a846. --- src/doc/rustdoc/src/unstable-features.md | 21 ++++ .../src/language-features/doc-spotlight.md | 30 ++++++ src/librustc_feature/active.rs | 3 + src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 2 + src/librustdoc/clean/types.rs | 1 + src/librustdoc/html/format.rs | 12 +++ src/librustdoc/html/render.rs | 87 ++++++++++++++++- src/librustdoc/html/static/main.js | 28 ++++++ src/librustdoc/html/static/rustdoc.css | 96 ++++++++++++++++++- src/librustdoc/html/static/themes/dark.css | 33 +++++++ src/librustdoc/html/static/themes/light.css | 33 +++++++ src/test/rustdoc/doc-spotlight.rs | 36 +++++++ .../feature-gate-doc_spotlight.rs | 4 + .../feature-gate-doc_spotlight.stderr | 12 +++ 15 files changed, 393 insertions(+), 9 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/doc-spotlight.md create mode 100644 src/test/rustdoc/doc-spotlight.rs create mode 100644 src/test/ui/feature-gates/feature-gate-doc_spotlight.rs create mode 100644 src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index eea674f2b84b9..d16c2a9d0342c 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -150,6 +150,27 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg]. [unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html [issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781 +### Adding your trait to the "Important Traits" dialog + +Rustdoc keeps a list of a few traits that are believed to be "fundamental" to a given type when +implemented on it. These traits are intended to be the primary interface for their types, and are +often the only thing available to be documented on their types. For this reason, Rustdoc will track +when a given type implements one of these traits and call special attention to it when a function +returns one of these types. This is the "Important Traits" dialog, visible as a circle-i button next +to the function, which, when clicked, shows the dialog. + +In the standard library, the traits that qualify for inclusion are `Iterator`, `io::Read`, and +`io::Write`. However, rather than being implemented as a hard-coded list, these traits have a +special marker attribute on them: `#[doc(spotlight)]`. This means that you could apply this +attribute to your own trait to include it in the "Important Traits" dialog in documentation. + +The `#[doc(spotlight)]` attribute currently requires the `#![feature(doc_spotlight)]` feature gate. +For more information, see [its chapter in the Unstable Book][unstable-spotlight] and [its tracking +issue][issue-spotlight]. + +[unstable-spotlight]: ../unstable-book/language-features/doc-spotlight.html +[issue-spotlight]: https://github.com/rust-lang/rust/issues/45040 + ### Exclude certain dependencies from documentation The standard library uses several dependencies which, in turn, use several types and traits from the diff --git a/src/doc/unstable-book/src/language-features/doc-spotlight.md b/src/doc/unstable-book/src/language-features/doc-spotlight.md new file mode 100644 index 0000000000000..8117755fef1c8 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/doc-spotlight.md @@ -0,0 +1,30 @@ +# `doc_spotlight` + +The tracking issue for this feature is: [#45040] + +The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute, +to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]` +attribute to a trait definition will make rustdoc print extra information for functions which return +a type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and +`io::Write` traits in the standard library. + +You can do this on your own traits, like this: + +``` +#![feature(doc_spotlight)] + +#[doc(spotlight)] +pub trait MyTrait {} + +pub struct MyStruct; +impl MyTrait for MyStruct {} + +/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`, +/// without having to write that yourself! +pub fn my_fn() -> MyStruct { MyStruct } +``` + +This feature was originally implemented in PR [#45039]. + +[#45040]: https://github.com/rust-lang/rust/issues/45040 +[#45039]: https://github.com/rust-lang/rust/pull/45039 diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 0da3693af4fb6..d7c310a8b4c8b 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -368,6 +368,9 @@ declare_features! ( /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), + /// Allows `#[doc(spotlight)]`. + (active, doc_spotlight, "1.22.0", Some(45040), None), + /// Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 78628b198a3c3..1387389981d26 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -12,7 +12,7 @@ use rustc_metadata::creader::LoadedMacro; use rustc_middle::ty; use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use crate::clean::{self, GetDefId, ToSource, TypeKind}; @@ -194,6 +194,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let generics = (cx.tcx.generics_of(did), predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); + 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, @@ -201,6 +202,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { generics, items: trait_items, bounds: supertrait_bounds, + is_spotlight, is_auto, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03d6853494cfc..8a4ee91df405f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1007,6 +1007,7 @@ impl Clean for hir::FnRetTy<'_> { impl Clean for doctree::Trait<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); + let is_spotlight = attrs.has_doc_flag(sym::spotlight); Item { name: Some(self.name.clean(cx)), attrs, @@ -1021,6 +1022,7 @@ impl Clean for doctree::Trait<'_> { items: self.items.iter().map(|ti| ti.clean(cx)).collect(), generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), + is_spotlight, is_auto: self.is_auto.clean(cx), }), } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c9ae67ded0a3f..5f6d9ecc0476d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -995,6 +995,7 @@ pub struct Trait { pub items: Vec, pub generics: Generics, pub bounds: Vec, + pub is_spotlight: bool, pub is_auto: bool, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a453a8b3dcb2a..0d8284029afc7 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -63,10 +63,22 @@ impl Buffer { Buffer { for_html: false, buffer: String::new() } } + crate fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + crate fn into_inner(self) -> String { self.buffer } + crate fn insert_str(&mut self, idx: usize, s: &str) { + self.buffer.insert_str(idx, s); + } + + crate fn push_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + // Intended for consumption by write! and writeln! (std::fmt) but without // the fmt::Result return type imposed by fmt::Write (and avoiding the trait // import). diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9fa3f6cc39610..940d7e87a183b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2410,7 +2410,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func f.generics.print() ) .len(); - write!(w, "
");
+    write!(w, "{}
", render_spotlight_traits(it));
     render_attributes(w, it, false);
     write!(
         w,
@@ -2612,7 +2612,12 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait)
         let name = m.name.as_ref().unwrap();
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
-        write!(w, "

", id = id); + write!( + w, + "

{extra}", + extra = render_spotlight_traits(m), + id = id + ); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, ""); render_stability_since(w, m, t); @@ -3559,6 +3564,76 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } } +fn render_spotlight_traits(item: &clean::Item) -> String { + match item.inner { + clean::FunctionItem(clean::Function { ref decl, .. }) + | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) + | clean::MethodItem(clean::Method { ref decl, .. }) + | clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => spotlight_decl(decl), + _ => String::new(), + } +} + +fn spotlight_decl(decl: &clean::FnDecl) -> String { + let mut out = Buffer::html(); + let mut trait_ = String::new(); + + if let Some(did) = decl.output.def_id() { + let c = cache(); + if let Some(impls) = c.impls.get(&did) { + for i in impls { + let impl_ = i.inner_impl(); + if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) { + if out.is_empty() { + out.push_str(&format!( + "

Important traits for {}

\ + ", + impl_.for_.print() + )); + trait_.push_str(&impl_.for_.print().to_string()); + } + + //use the "where" class here to make it small + out.push_str(&format!( + "{}", + impl_.print() + )); + let t_did = impl_.trait_.def_id().unwrap(); + for it in &impl_.items { + if let clean::TypedefItem(ref tydef, _) = it.inner { + out.push_str(" "); + assoc_type( + &mut out, + it, + &[], + Some(&tydef.type_), + AssocItemLink::GotoSource(t_did, &FxHashSet::default()), + "", + ); + out.push_str(";"); + } + } + } + } + } + } + + if !out.is_empty() { + out.insert_str( + 0, + &format!( + "
ⓘ\ + Important traits for {}
\ +
", + trait_ + ), + ); + out.push_str("
"); + } + + out.into_inner() +} + fn render_impl( w: &mut Buffer, cx: &Context, @@ -3665,12 +3740,14 @@ fn render_impl( (true, " hidden") }; match item.inner { - clean::MethodItem(clean::Method { .. }) - | clean::TyMethodItem(clean::TyMethod { .. }) => { + clean::MethodItem(clean::Method { ref decl, .. }) + | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => { // 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)); - write!(w, "

", id, item_type, extra_class); + write!(w, "

", id, item_type, extra_class); + write!(w, "{}", spotlight_decl(decl)); + write!(w, ""); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, ""); render_stability_since_raw(w, item.stable_since(), outer_version); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 336c691ac1c24..524a841e098b7 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -365,6 +365,7 @@ function defocusSearchBar() { function handleEscape(ev) { var help = getHelpElement(); var search = getSearchElement(); + hideModal(); if (hasClass(help, "hidden") === false) { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { @@ -397,6 +398,7 @@ function defocusSearchBar() { case "s": case "S": displayHelp(false, ev); + hideModal(); ev.preventDefault(); focusSearchBar(); break; @@ -409,6 +411,7 @@ function defocusSearchBar() { case "?": if (ev.shiftKey) { + hideModal(); displayHelp(true, ev); } break; @@ -2636,6 +2639,31 @@ function defocusSearchBar() { }); }()); + function showModal(content) { + var modal = document.createElement("div"); + modal.id = "important"; + addClass(modal, "modal"); + modal.innerHTML = "
✕" + + "
" + content + + "
"; + document.getElementsByTagName("body")[0].appendChild(modal); + document.getElementById("modal-close").onclick = hideModal; + modal.onclick = hideModal; + } + + function hideModal() { + var modal = document.getElementById("important"); + if (modal) { + modal.parentNode.removeChild(modal); + } + } + + onEachLazy(document.getElementsByClassName("important-traits"), function(e) { + e.onclick = function() { + showModal(e.lastElementChild.innerHTML); + }; + }); + // In the search display, allows to switch between tabs. function printTab(nb) { if (nb === 0 || nb === 1 || nb === 2) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 15a0c76ceeafb..3b2a28a0f5e45 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -146,9 +146,12 @@ code, pre, a.test-arrow { border-radius: 3px; padding: 0 0.1em; } -.docblock pre code, .docblock-short pre code { +.docblock pre code, .docblock-short pre code, .docblock code.spotlight { padding: 0; } +.docblock code.spotlight :last-child { + padding-bottom: 0.6em; +} pre { padding: 14px; } @@ -523,7 +526,7 @@ h4 > code, h3 > code, .invisible > code { font-size: 0.8em; } -.content .methods > div { +.content .methods > div:not(.important-traits) { margin-left: 40px; margin-bottom: 15px; } @@ -1098,7 +1101,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 20px; } -.tooltip .tooltiptext { +.important-traits .tooltip .tooltiptext { border: 1px solid; font-weight: normal; } @@ -1144,6 +1147,17 @@ pre.rust { font-size: 16px; } +.important-traits { + cursor: pointer; + z-index: 2; +} + +h4 > .important-traits { + position: absolute; + left: -44px; + top: 2px; +} + #all-types { text-align: center; border: 1px solid; @@ -1370,6 +1384,12 @@ pre.rust { z-index: 1; } + h4 > .important-traits { + position: absolute; + left: -22px; + top: 24px; + } + #titles > div > div.count { float: left; width: 100%; @@ -1472,12 +1492,82 @@ pre.rust { } } +.modal { + position: fixed; + width: 100vw; + height: 100vh; + z-index: 10000; + top: 0; + left: 0; +} + +.modal-content { + display: block; + max-width: 60%; + min-width: 200px; + padding: 8px; + top: 40%; + position: absolute; + left: 50%; + transform: translate(-50%, -40%); + border: 1px solid; + border-radius: 4px; + border-top-right-radius: 0; +} + +.modal-content > .docblock { + margin: 0; +} + h3.important { margin: 0; margin-bottom: 13px; font-size: 19px; } +.modal-content > .docblock > code.content { + margin: 0; + padding: 0; + font-size: 20px; +} + +.modal-content > .close { + position: absolute; + font-weight: 900; + right: -25px; + top: -1px; + font-size: 18px; + width: 25px; + padding-right: 2px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + text-align: center; + border: 1px solid; + border-right: 0; + cursor: pointer; +} + +.modal-content > .whiter { + height: 25px; + position: absolute; + width: 3px; + right: -2px; + top: 0px; +} + +#main > div.important-traits { + position: absolute; + left: -24px; + margin-top: 16px; +} + +.content > .methods > .method > div.important-traits { + position: absolute; + font-weight: 400; + left: -42px; + margin-top: 2px; +} + kbd { display: inline-block; padding: 3px 5px; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 41dcb5c24507c..daa5ccf34bb18 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -337,6 +337,12 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } +.important-traits .tooltip .tooltiptext { + background-color: white; + color: black; + border-color: black; +} + #titles > div:not(.selected) { background-color: #252525; border-top-color: #252525; @@ -350,6 +356,33 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } +.modal { + background-color: rgba(0,0,0,0.3); +} + +.modal-content { + background-color: #272727; + border-color: #999; +} + +.modal-content > .close { + background-color: #272727; + border-color: #999; +} + +.modal-content > .close:hover { + background-color: #ff1f1f; + color: white; +} + +.modal-content > .whiter { + background-color: #272727; +} + +.modal-content > .close:hover + .whiter { + background-color: #ff1f1f; +} + @media (max-width: 700px) { .sidebar-menu { background-color: #505050; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 386fe2398e63a..aa7df01dc02b3 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -331,6 +331,12 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } +.important-traits .tooltip .tooltiptext { + background-color: white; + color: black; + border-color: black; +} + #titles > div:not(.selected) { background-color: #e6e6e6; border-top-color: #e6e6e6; @@ -344,6 +350,33 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } +.modal { + background-color: rgba(0,0,0,0.3); +} + +.modal-content { + background-color: #eee; + border-color: #999; +} + +.modal-content > .close { + background-color: #eee; + border-color: #999; +} + +.modal-content > .close:hover { + background-color: #ff1f1f; + color: white; +} + +.modal-content > .whiter { + background-color: #eee; +} + +.modal-content > .close:hover + .whiter { + background-color: #ff1f1f; +} + @media (max-width: 700px) { .sidebar-menu { background-color: #F1F1F1; diff --git a/src/test/rustdoc/doc-spotlight.rs b/src/test/rustdoc/doc-spotlight.rs new file mode 100644 index 0000000000000..ddd46c3c2155f --- /dev/null +++ b/src/test/rustdoc/doc-spotlight.rs @@ -0,0 +1,36 @@ +#![feature(doc_spotlight)] + +pub struct Wrapper { + inner: T, +} + +impl SomeTrait for Wrapper {} + +#[doc(spotlight)] +pub trait SomeTrait { + // @has doc_spotlight/trait.SomeTrait.html + // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' + fn wrap_me(self) -> Wrapper where Self: Sized { + Wrapper { + inner: self, + } + } +} + +pub struct SomeStruct; +impl SomeTrait for SomeStruct {} + +impl SomeStruct { + // @has doc_spotlight/struct.SomeStruct.html + // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' + // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' + pub fn new() -> SomeStruct { + SomeStruct + } +} + +// @has doc_spotlight/fn.bare_fn.html +// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' +pub fn bare_fn() -> SomeStruct { + SomeStruct +} diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs new file mode 100644 index 0000000000000..452b45b34456b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs @@ -0,0 +1,4 @@ +#[doc(spotlight)] //~ ERROR: `#[doc(spotlight)]` is experimental +trait SomeTrait {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr new file mode 100644 index 0000000000000..010d74054a412 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[doc(spotlight)]` is experimental + --> $DIR/feature-gate-doc_spotlight.rs:1:1 + | +LL | #[doc(spotlight)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #45040 for more information + = help: add `#![feature(doc_spotlight)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 3cecd6003b3eb15168421084a27223596517899c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 12:54:33 -0700 Subject: [PATCH 62/69] Revert "Remove spotlight usage" This reverts commit 13c6d5819aae3c0de6a90e7f17ea967bf4487cbb. --- src/libcore/future/future.rs | 1 + src/libcore/iter/traits/iterator.rs | 1 + src/libcore/lib.rs | 1 + src/librustc_ast_passes/feature_gate.rs | 1 + src/librustc_span/symbol.rs | 2 ++ src/libstd/io/mod.rs | 2 ++ src/libstd/lib.rs | 1 + 7 files changed, 9 insertions(+) diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index abf461338d80a..733ebdc0e97f2 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -24,6 +24,7 @@ use crate::task::{Context, Poll}; /// `.await` the value. /// /// [`Waker`]: ../task/struct.Waker.html +#[doc(spotlight)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index ce4be973140e5..692eed80c0252 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -92,6 +92,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} label = "`{Self}` is not an iterator", message = "`{Self}` is not an iterator" )] +#[doc(spotlight)] #[must_use = "iterators are lazy and do nothing unless consumed"] pub trait Iterator { /// The type of the elements being iterated over. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 88991dea7d43e..c2dc3e5985f34 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -96,6 +96,7 @@ #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_spotlight))] #![feature(duration_consts_2)] #![feature(extern_types)] #![feature(fundamental)] diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index a7b0c9cf81be6..b424c8afb3471 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -253,6 +253,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { include => external_doc cfg => doc_cfg masked => doc_masked + spotlight => doc_spotlight alias => doc_alias keyword => doc_keyword ); diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 75f588918a020..ccb6ccb57fa40 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -400,6 +400,7 @@ symbols! { doc_cfg, doc_keyword, doc_masked, + doc_spotlight, doctest, document_private_items, dotdot_in_tuple_patterns, @@ -968,6 +969,7 @@ symbols! { soft, specialization, speed, + spotlight, sqrtf32, sqrtf64, sse4a_target_feature, diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 717d2868abf98..d5af4f25102d1 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -499,6 +499,7 @@ where /// [`&str`]: ../../std/primitive.str.html /// [slice]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] +#[doc(spotlight)] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -1261,6 +1262,7 @@ impl Initializer { /// /// [`write_all`]: #method.write_all #[stable(feature = "rust1", since = "1.0.0")] +#[doc(spotlight)] pub trait Write { /// Write a buffer into this writer, returning how many bytes were written. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4fd5e238eea11..cbc24009a949a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -261,6 +261,7 @@ #![feature(doc_cfg)] #![feature(doc_keyword)] #![feature(doc_masked)] +#![cfg_attr(not(bootstrap), feature(doc_spotlight))] #![feature(dropck_eyepatch)] #![feature(duration_constants)] #![feature(exact_size_is_empty)] From c90fb7185a5febb00b7f8ccb49abceacd41bad6e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 14:13:47 -0700 Subject: [PATCH 63/69] Move spotlight next to the return type --- src/librustdoc/html/render.rs | 34 +++++++++----------------- src/librustdoc/html/static/rustdoc.css | 16 ++---------- 2 files changed, 14 insertions(+), 36 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 940d7e87a183b..1a96656b6f23c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2410,12 +2410,12 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func f.generics.print() ) .len(); - write!(w, "{}
", render_spotlight_traits(it));
+    write!(w, "
");
     render_attributes(w, it, false);
     write!(
         w,
         "{vis}{constness}{asyncness}{unsafety}{abi}fn \
-           {name}{generics}{decl}{where_clause}
", + {name}{generics}{decl}{spotlight}{where_clause}
", vis = it.visibility.print_with_space(), constness = f.header.constness.print_with_space(), asyncness = f.header.asyncness.print_with_space(), @@ -2425,7 +2425,8 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func generics = f.generics.print(), where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true }, decl = Function { decl: &f.decl, header_len, indent: 0, asyncness: f.header.asyncness } - .print() + .print(), + spotlight = spotlight_decl(&f.decl), ); document(w, cx, it) } @@ -2614,9 +2615,8 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait) let id = cx.derive_id(format!("{}.{}", item_type, name)); write!( w, - "

{extra}", - extra = render_spotlight_traits(m), - id = id + "

", + id = id, ); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, ""); @@ -2931,7 +2931,7 @@ fn render_assoc_item( write!( w, "{}{}{}{}{}{}{}fn {name}\ - {generics}{decl}{where_clause}", + {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, meth.visibility.print_with_space(), header.constness.print_with_space(), @@ -2943,6 +2943,7 @@ fn render_assoc_item( name = name, generics = g.print(), decl = Function { decl: d, header_len, indent, asyncness: header.asyncness }.print(), + spotlight = spotlight_decl(&d), where_clause = WhereClause { gens: g, indent, end_newline } ) } @@ -3564,16 +3565,6 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } } -fn render_spotlight_traits(item: &clean::Item) -> String { - match item.inner { - clean::FunctionItem(clean::Function { ref decl, .. }) - | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) - | clean::MethodItem(clean::Method { ref decl, .. }) - | clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => spotlight_decl(decl), - _ => String::new(), - } -} - fn spotlight_decl(decl: &clean::FnDecl) -> String { let mut out = Buffer::html(); let mut trait_ = String::new(); @@ -3622,13 +3613,13 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { out.insert_str( 0, &format!( - "
ⓘ\ + "
ⓘ\ Important traits for {}
\
", trait_ ), ); - out.push_str("
"); + out.push_str("
"); } out.into_inner() @@ -3740,13 +3731,12 @@ fn render_impl( (true, " hidden") }; match item.inner { - clean::MethodItem(clean::Method { ref decl, .. }) - | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => { + clean::MethodItem(clean::Method { .. }) + | clean::TyMethodItem(clean::TyMethod { .. }) => { // 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)); write!(w, "

", id, item_type, extra_class); - write!(w, "{}", spotlight_decl(decl)); write!(w, ""); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, ""); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 3b2a28a0f5e45..b780cf5dafb49 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1082,7 +1082,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 16px; } -.tooltip:hover .tooltiptext { +.important-traits:hover .tooltiptext { display: inline; } @@ -1150,6 +1150,7 @@ pre.rust { .important-traits { cursor: pointer; z-index: 2; + margin-left: 5px; } h4 > .important-traits { @@ -1555,19 +1556,6 @@ h3.important { top: 0px; } -#main > div.important-traits { - position: absolute; - left: -24px; - margin-top: 16px; -} - -.content > .methods > .method > div.important-traits { - position: absolute; - font-weight: 400; - left: -42px; - margin-top: 2px; -} - kbd { display: inline-block; padding: 3px 5px; From 734afb48300ad840118c2a6d140ec8bfeecf866e Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 17:18:04 -0700 Subject: [PATCH 64/69] Make spotlight show on hover This makes the spotlight show on hover instead of click. Clicks can be used to persist it, which is also what's used on mobile. --- src/librustdoc/html/render.rs | 16 +-- src/librustdoc/html/static/main.js | 21 +--- src/librustdoc/html/static/rustdoc.css | 104 ++++++++------------ src/librustdoc/html/static/themes/dark.css | 34 +------ src/librustdoc/html/static/themes/light.css | 34 +------ 5 files changed, 53 insertions(+), 156 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1a96656b6f23c..3f49420492eda 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2613,11 +2613,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait) let name = m.name.as_ref().unwrap(); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); - write!( - w, - "

", - id = id, - ); + write!(w, "

", id = id,); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, ""); render_stability_since(w, m, t); @@ -3612,14 +3608,10 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { if !out.is_empty() { out.insert_str( 0, - &format!( - "
ⓘ\ - Important traits for {}
\ -
", - trait_ - ), + "ⓘ
" + ); - out.push_str("
"); + out.push_str("
"); } out.into_inner() diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 524a841e098b7..fcbcae096fccd 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2639,28 +2639,13 @@ function defocusSearchBar() { }); }()); - function showModal(content) { - var modal = document.createElement("div"); - modal.id = "important"; - addClass(modal, "modal"); - modal.innerHTML = "
✕" + - "
" + content + - "
"; - document.getElementsByTagName("body")[0].appendChild(modal); - document.getElementById("modal-close").onclick = hideModal; - modal.onclick = hideModal; - } - - function hideModal() { - var modal = document.getElementById("important"); - if (modal) { - modal.parentNode.removeChild(modal); - } + function showImportantTraits(content) { + let list = content.classList } onEachLazy(document.getElementsByClassName("important-traits"), function(e) { e.onclick = function() { - showModal(e.lastElementChild.innerHTML); + e.getElementsByClassName('important-traits-tooltiptext')[0].classList.toggle("force-tooltip") }; }); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index b780cf5dafb49..bc7507f9af8fc 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1082,10 +1082,6 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 16px; } -.important-traits:hover .tooltiptext { - display: inline; -} - .tooltip .tooltiptext::after { content: " "; position: absolute; @@ -1101,9 +1097,46 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 20px; } -.important-traits .tooltip .tooltiptext { - border: 1px solid; - font-weight: normal; +.important-traits-tooltip { + display: inline-block; + cursor: pointer; +} + +.important-traits:hover .important-traits-tooltiptext, +.important-traits .important-traits-tooltiptext.force-tooltip { + display: inline-block; +} + +.important-traits .important-traits-tooltiptext { + display: none; + padding: 5px 3px 3px 3px; + border-radius: 6px; + margin-left: 5px; + z-index: 10; + font-size: 16px; + cursor: default; + position: absolute; + /* Themes will override the color here, + but it's necessary to make it opaque */ + background-color: #eee; + border: 1px solid #999; +} + +.important-traits-tooltip::after { + /* The margin on the tooltip does not capture hover events, + this extends the area of hover enough so that mouse hover is not + lost when moving the mouse to the tooltip */ + content: "\00a0\00a0\00a0"; +} + +.important-traits .important, .important-traits .docblock { + margin: 0; +} + +.important-traits .docblock code.content{ + margin: 0; + padding: 0; + font-size: 20px; } pre.rust { @@ -1493,69 +1526,12 @@ h4 > .important-traits { } } -.modal { - position: fixed; - width: 100vw; - height: 100vh; - z-index: 10000; - top: 0; - left: 0; -} - -.modal-content { - display: block; - max-width: 60%; - min-width: 200px; - padding: 8px; - top: 40%; - position: absolute; - left: 50%; - transform: translate(-50%, -40%); - border: 1px solid; - border-radius: 4px; - border-top-right-radius: 0; -} - -.modal-content > .docblock { - margin: 0; -} - h3.important { margin: 0; margin-bottom: 13px; font-size: 19px; } -.modal-content > .docblock > code.content { - margin: 0; - padding: 0; - font-size: 20px; -} - -.modal-content > .close { - position: absolute; - font-weight: 900; - right: -25px; - top: -1px; - font-size: 18px; - width: 25px; - padding-right: 2px; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - text-align: center; - border: 1px solid; - border-right: 0; - cursor: pointer; -} - -.modal-content > .whiter { - height: 25px; - position: absolute; - width: 3px; - right: -2px; - top: 0px; -} - kbd { display: inline-block; padding: 3px 5px; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index daa5ccf34bb18..cdfe01f216df3 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -337,10 +337,9 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } -.important-traits .tooltip .tooltiptext { - background-color: white; - color: black; - border-color: black; +.important-traits-tooltiptext { + background-color: #111 !important; + border-color: #777 !important; } #titles > div:not(.selected) { @@ -356,33 +355,6 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } -.modal { - background-color: rgba(0,0,0,0.3); -} - -.modal-content { - background-color: #272727; - border-color: #999; -} - -.modal-content > .close { - background-color: #272727; - border-color: #999; -} - -.modal-content > .close:hover { - background-color: #ff1f1f; - color: white; -} - -.modal-content > .whiter { - background-color: #272727; -} - -.modal-content > .close:hover + .whiter { - background-color: #ff1f1f; -} - @media (max-width: 700px) { .sidebar-menu { background-color: #505050; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index aa7df01dc02b3..8ffb935a37851 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -331,10 +331,9 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } -.important-traits .tooltip .tooltiptext { - background-color: white; - color: black; - border-color: black; +.important-traits-tooltiptext { + background-color: #eee !important; + border-color: #999 !important; } #titles > div:not(.selected) { @@ -350,33 +349,6 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } -.modal { - background-color: rgba(0,0,0,0.3); -} - -.modal-content { - background-color: #eee; - border-color: #999; -} - -.modal-content > .close { - background-color: #eee; - border-color: #999; -} - -.modal-content > .close:hover { - background-color: #ff1f1f; - color: white; -} - -.modal-content > .whiter { - background-color: #eee; -} - -.modal-content > .close:hover + .whiter { - background-color: #ff1f1f; -} - @media (max-width: 700px) { .sidebar-menu { background-color: #F1F1F1; From ae6c7e6f406fa5129c865f3af4414ff6e0bfe739 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 15 Jul 2020 08:58:10 -0700 Subject: [PATCH 65/69] Review comments for JS --- src/librustdoc/html/static/main.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index fcbcae096fccd..082f9cca064f1 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -365,7 +365,6 @@ function defocusSearchBar() { function handleEscape(ev) { var help = getHelpElement(); var search = getSearchElement(); - hideModal(); if (hasClass(help, "hidden") === false) { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { @@ -398,7 +397,6 @@ function defocusSearchBar() { case "s": case "S": displayHelp(false, ev); - hideModal(); ev.preventDefault(); focusSearchBar(); break; @@ -411,7 +409,6 @@ function defocusSearchBar() { case "?": if (ev.shiftKey) { - hideModal(); displayHelp(true, ev); } break; @@ -2639,13 +2636,10 @@ function defocusSearchBar() { }); }()); - function showImportantTraits(content) { - let list = content.classList - } - onEachLazy(document.getElementsByClassName("important-traits"), function(e) { e.onclick = function() { - e.getElementsByClassName('important-traits-tooltiptext')[0].classList.toggle("force-tooltip") + this.getElementsByClassName('important-traits-tooltiptext')[0] + .classList.toggle("force-tooltip"); }; }); From 0625b2981351f93e7d0cd7e207a52e5605d2816b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 15 Jul 2020 09:13:18 -0700 Subject: [PATCH 66/69] Add Ayu theme for spotlight --- src/librustdoc/html/static/themes/ayu.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index bc21c28750fd8..ae273c5dc397c 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -394,6 +394,11 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent #314559 transparent transparent; } +.important-traits-tooltiptext { + background-color: #314559 !important; + border-color: #5c6773 !important; +} + #titles > div.selected { background-color: #141920 !important; border-bottom: 1px solid #ffb44c !important; From a474b272f5bccd955afad5935c8e3cefc4aa88e4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 15 Jul 2020 09:29:34 -0700 Subject: [PATCH 67/69] Remove !important on border-color and background-color --- src/librustdoc/html/static/rustdoc.css | 5 +---- src/librustdoc/html/static/themes/ayu.css | 4 ++-- src/librustdoc/html/static/themes/dark.css | 4 ++-- src/librustdoc/html/static/themes/light.css | 4 ++-- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index bc7507f9af8fc..5b336c3751528 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1116,10 +1116,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 16px; cursor: default; position: absolute; - /* Themes will override the color here, - but it's necessary to make it opaque */ - background-color: #eee; - border: 1px solid #999; + border: 1px solid; } .important-traits-tooltip::after { diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index ae273c5dc397c..b436997da5816 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -395,8 +395,8 @@ pre.ignore:hover, .information:hover + pre.ignore { } .important-traits-tooltiptext { - background-color: #314559 !important; - border-color: #5c6773 !important; + background-color: #314559; + border-color: #5c6773; } #titles > div.selected { diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index cdfe01f216df3..f4ca67f8540a9 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -338,8 +338,8 @@ pre.ignore:hover, .information:hover + pre.ignore { } .important-traits-tooltiptext { - background-color: #111 !important; - border-color: #777 !important; + background-color: #111; + border-color: #777; } #titles > div:not(.selected) { diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 8ffb935a37851..b5a0ba4775c24 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -332,8 +332,8 @@ pre.ignore:hover, .information:hover + pre.ignore { } .important-traits-tooltiptext { - background-color: #eee !important; - border-color: #999 !important; + background-color: #eee; + border-color: #999; } #titles > div:not(.selected) { From c621a54eeb71248927dff8ac0c76f279cf756f28 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 16 Jul 2020 09:01:30 -0700 Subject: [PATCH 68/69] Don't position:relative on all pres We need it for run buttons (https://github.com/rust-lang/rust/pull/44671), but not function defs --- src/librustdoc/html/static/rustdoc.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 5b336c3751528..f5551446bf220 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1136,8 +1136,13 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 20px; } -pre.rust { +/* Example code has the "Run" button that + needs to be positioned relative to the pre */ +pre.rust.rust-example-rendered { position: relative; +} + +pre.rust { tab-size: 4; -moz-tab-size: 4; } From 5b287f6ce1ba6746bf26780006a2340634ae7719 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 16 Jul 2020 13:47:37 -0400 Subject: [PATCH 69/69] Set shell for github actions CI --- .github/workflows/ci.yml | 77 ++++++++++++++++++++++++++++++++++++ src/ci/github-actions/ci.yml | 20 ++++++++++ 2 files changed, 97 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29421895a9482..99140bec17029 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,59 +66,77 @@ jobs: if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh + shell: bash env: EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" if: success() && !env.SKIP_JOB - name: decide whether to skip this job run: src/ci/scripts/should-skip-this.sh + shell: bash if: success() && !env.SKIP_JOB - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh + shell: bash if: success() && !env.SKIP_JOB - name: show the current environment run: src/ci/scripts/dump-environment.sh + shell: bash if: success() && !env.SKIP_JOB - name: install awscli run: src/ci/scripts/install-awscli.sh + shell: bash if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh + shell: bash if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh + shell: bash if: success() && !env.SKIP_JOB - name: install WIX run: src/ci/scripts/install-wix.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MSYS2 run: src/ci/scripts/install-msys2.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh + shell: bash if: success() && !env.SKIP_JOB - name: install ninja run: src/ci/scripts/install-ninja.sh + shell: bash if: success() && !env.SKIP_JOB - name: enable ipv6 on Docker run: src/ci/scripts/enable-docker-ipv6.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure line endings are correct run: src/ci/scripts/verify-line-endings.sh + shell: bash if: success() && !env.SKIP_JOB - name: run the build run: src/ci/scripts/run-build-from-ci.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -126,6 +144,7 @@ jobs: if: success() && !env.SKIP_JOB - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" @@ -166,59 +185,77 @@ jobs: if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh + shell: bash env: EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" if: success() && !env.SKIP_JOB - name: decide whether to skip this job run: src/ci/scripts/should-skip-this.sh + shell: bash if: success() && !env.SKIP_JOB - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh + shell: bash if: success() && !env.SKIP_JOB - name: show the current environment run: src/ci/scripts/dump-environment.sh + shell: bash if: success() && !env.SKIP_JOB - name: install awscli run: src/ci/scripts/install-awscli.sh + shell: bash if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh + shell: bash if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh + shell: bash if: success() && !env.SKIP_JOB - name: install WIX run: src/ci/scripts/install-wix.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MSYS2 run: src/ci/scripts/install-msys2.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh + shell: bash if: success() && !env.SKIP_JOB - name: install ninja run: src/ci/scripts/install-ninja.sh + shell: bash if: success() && !env.SKIP_JOB - name: enable ipv6 on Docker run: src/ci/scripts/enable-docker-ipv6.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure line endings are correct run: src/ci/scripts/verify-line-endings.sh + shell: bash if: success() && !env.SKIP_JOB - name: run the build run: src/ci/scripts/run-build-from-ci.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -226,6 +263,7 @@ jobs: if: success() && !env.SKIP_JOB - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" @@ -484,59 +522,77 @@ jobs: if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh + shell: bash env: EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" if: success() && !env.SKIP_JOB - name: decide whether to skip this job run: src/ci/scripts/should-skip-this.sh + shell: bash if: success() && !env.SKIP_JOB - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh + shell: bash if: success() && !env.SKIP_JOB - name: show the current environment run: src/ci/scripts/dump-environment.sh + shell: bash if: success() && !env.SKIP_JOB - name: install awscli run: src/ci/scripts/install-awscli.sh + shell: bash if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh + shell: bash if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh + shell: bash if: success() && !env.SKIP_JOB - name: install WIX run: src/ci/scripts/install-wix.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MSYS2 run: src/ci/scripts/install-msys2.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh + shell: bash if: success() && !env.SKIP_JOB - name: install ninja run: src/ci/scripts/install-ninja.sh + shell: bash if: success() && !env.SKIP_JOB - name: enable ipv6 on Docker run: src/ci/scripts/enable-docker-ipv6.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure line endings are correct run: src/ci/scripts/verify-line-endings.sh + shell: bash if: success() && !env.SKIP_JOB - name: run the build run: src/ci/scripts/run-build-from-ci.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -544,6 +600,7 @@ jobs: if: success() && !env.SKIP_JOB - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" @@ -610,59 +667,77 @@ jobs: if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - name: add extra environment variables run: src/ci/scripts/setup-environment.sh + shell: bash env: EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" if: success() && !env.SKIP_JOB - name: decide whether to skip this job run: src/ci/scripts/should-skip-this.sh + shell: bash if: success() && !env.SKIP_JOB - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh + shell: bash if: success() && !env.SKIP_JOB - name: show the current environment run: src/ci/scripts/dump-environment.sh + shell: bash if: success() && !env.SKIP_JOB - name: install awscli run: src/ci/scripts/install-awscli.sh + shell: bash if: success() && !env.SKIP_JOB - name: install sccache run: src/ci/scripts/install-sccache.sh + shell: bash if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh + shell: bash if: success() && !env.SKIP_JOB - name: install WIX run: src/ci/scripts/install-wix.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MSYS2 run: src/ci/scripts/install-msys2.sh + shell: bash if: success() && !env.SKIP_JOB - name: install MinGW run: src/ci/scripts/install-mingw.sh + shell: bash if: success() && !env.SKIP_JOB - name: install ninja run: src/ci/scripts/install-ninja.sh + shell: bash if: success() && !env.SKIP_JOB - name: enable ipv6 on Docker run: src/ci/scripts/enable-docker-ipv6.sh + shell: bash if: success() && !env.SKIP_JOB - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash if: success() && !env.SKIP_JOB - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh + shell: bash if: success() && !env.SKIP_JOB - name: ensure line endings are correct run: src/ci/scripts/verify-line-endings.sh + shell: bash if: success() && !env.SKIP_JOB - name: run the build run: src/ci/scripts/run-build-from-ci.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -670,6 +745,7 @@ jobs: if: success() && !env.SKIP_JOB - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh + shell: bash env: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" @@ -694,6 +770,7 @@ jobs: fetch-depth: 2 - name: publish toolstate run: src/ci/publish_toolstate.sh + shell: bash env: TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" if: success() && !env.SKIP_JOB diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 8545ec15d3280..0b3b77f217dbd 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -95,6 +95,7 @@ x--expand-yaml-anchors--remove: - name: add extra environment variables run: src/ci/scripts/setup-environment.sh + shell: bash env: # Since it's not possible to merge `${{ matrix.env }}` with the other # variables in `job..env`, the variables defined in the matrix @@ -105,54 +106,67 @@ x--expand-yaml-anchors--remove: - name: decide whether to skip this job run: src/ci/scripts/should-skip-this.sh + shell: bash <<: *step - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh + shell: bash <<: *step - name: show the current environment run: src/ci/scripts/dump-environment.sh + shell: bash <<: *step - name: install awscli run: src/ci/scripts/install-awscli.sh + shell: bash <<: *step - name: install sccache run: src/ci/scripts/install-sccache.sh + shell: bash <<: *step - name: install clang run: src/ci/scripts/install-clang.sh + shell: bash <<: *step - name: install WIX run: src/ci/scripts/install-wix.sh + shell: bash <<: *step - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh + shell: bash <<: *step - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash <<: *step - name: install MSYS2 run: src/ci/scripts/install-msys2.sh + shell: bash <<: *step - name: install MinGW run: src/ci/scripts/install-mingw.sh + shell: bash <<: *step - name: install ninja run: src/ci/scripts/install-ninja.sh + shell: bash <<: *step - name: enable ipv6 on Docker run: src/ci/scripts/enable-docker-ipv6.sh + shell: bash <<: *step # Disable automatic line ending conversion (again). On Windows, when we're @@ -162,18 +176,22 @@ x--expand-yaml-anchors--remove: # appropriate line endings. - name: disable git crlf conversion run: src/ci/scripts/disable-git-crlf-conversion.sh + shell: bash <<: *step - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh + shell: bash <<: *step - name: ensure line endings are correct run: src/ci/scripts/verify-line-endings.sh + shell: bash <<: *step - name: run the build run: src/ci/scripts/run-build-from-ci.sh + shell: bash env: AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} @@ -182,6 +200,7 @@ x--expand-yaml-anchors--remove: - name: upload artifacts to S3 run: src/ci/scripts/upload-artifacts.sh + shell: bash env: AWS_ACCESS_KEY_ID: ${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }} @@ -620,6 +639,7 @@ jobs: - name: publish toolstate run: src/ci/publish_toolstate.sh + shell: bash env: TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }} <<: *step