From d122a0813acc162805683eb207a3a9e659c462d5 Mon Sep 17 00:00:00 2001 From: George O'Hara Date: Mon, 27 Sep 2021 13:18:22 +0100 Subject: [PATCH 01/17] Issue 89193 --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 33 +++++++++--- src/test/ui/simd/issue-89193.rs | 53 ++++++++++++++++++++ 2 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/simd/issue-89193.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 37b3279fb8096..8494baaa56d4c 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{sym, symbol::kw, Span, Symbol}; use rustc_target::abi::{self, HasDataLayout, Primitive}; -use rustc_target::spec::PanicStrategy; +use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use std::cmp::Ordering; use std::iter; @@ -1187,11 +1187,28 @@ fn generic_simd_intrinsic( // FIXME: use: // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 - fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: u64, no_pointers: usize) -> String { + fn llvm_vector_str( + elem_ty: Ty<'_>, + vec_len: u64, + no_pointers: usize, + bx: &Builder<'a, 'll, 'tcx>, + ) -> String { let p0s: String = "p0".repeat(no_pointers); match *elem_ty.kind() { - ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), - ty::Uint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::Int(v) => format!( + "v{}{}i{}", + vec_len, + p0s, + // Normalize to prevent crash if v: IntTy::Isize + v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() + ), + ty::Uint(v) => format!( + "v{}{}i{}", + vec_len, + p0s, + // Normalize to prevent crash if v: UIntTy::Usize + v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() + ), ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), _ => unreachable!(), } @@ -1327,11 +1344,11 @@ fn generic_simd_intrinsic( // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); - let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); - let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); let llvm_intrinsic = format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str); @@ -1455,11 +1472,11 @@ fn generic_simd_intrinsic( // Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); - let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); - let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); let llvm_intrinsic = format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str); diff --git a/src/test/ui/simd/issue-89193.rs b/src/test/ui/simd/issue-89193.rs new file mode 100644 index 0000000000000..d6ebea10b7ad8 --- /dev/null +++ b/src/test/ui/simd/issue-89193.rs @@ -0,0 +1,53 @@ +// run-pass + +// Test that simd gather instructions on slice of usize don't cause crash +// See issue #89183 - https://github.com/rust-lang/rust/issues/89193 + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct x4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather(x: T, y: U, z: V) -> T; +} + +fn main() { + let x: [usize; 4] = [10, 11, 12, 13]; + let default = x4(0_usize, 1, 2, 3); + let mask = x4(1_i32, 1, 1, 1); + let expected = x4(10_usize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const usize; + let pointers = x4( + pointer.offset(0) as *const usize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } + + // and again for isize + let x: [isize; 4] = [10, 11, 12, 13]; + let default = x4(0_isize, 1, 2, 3); + let expected = x4(10_isize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const isize; + let pointers = x4( + pointer.offset(0) as *const isize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } + +} + From 88113c554d2edd51050ca7f51f94ff9f83a297b5 Mon Sep 17 00:00:00 2001 From: George O'Hara <50339401+gcohara@users.noreply.github.com> Date: Mon, 27 Sep 2021 14:08:15 +0100 Subject: [PATCH 02/17] Update issue-89193.rs --- src/test/ui/simd/issue-89193.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/ui/simd/issue-89193.rs b/src/test/ui/simd/issue-89193.rs index d6ebea10b7ad8..79c4e6a312c0d 100644 --- a/src/test/ui/simd/issue-89193.rs +++ b/src/test/ui/simd/issue-89193.rs @@ -19,7 +19,7 @@ fn main() { let default = x4(0_usize, 1, 2, 3); let mask = x4(1_i32, 1, 1, 1); let expected = x4(10_usize, 11, 12, 13); - + unsafe { let pointer = &x[0] as *const usize; let pointers = x4( @@ -36,7 +36,7 @@ fn main() { let x: [isize; 4] = [10, 11, 12, 13]; let default = x4(0_isize, 1, 2, 3); let expected = x4(10_isize, 11, 12, 13); - + unsafe { let pointer = &x[0] as *const isize; let pointers = x4( @@ -48,6 +48,4 @@ fn main() { let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } - } - From cb501a6fe6cdb1928611b7193dec96f3d7bd2293 Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sat, 2 Oct 2021 14:25:53 -0700 Subject: [PATCH 03/17] Move items related to computing diffs to a separate file --- src/tools/compiletest/src/compute_diff.rs | 106 +++++++++++++++++++++ src/tools/compiletest/src/main.rs | 1 + src/tools/compiletest/src/runtest.rs | 108 +--------------------- 3 files changed, 109 insertions(+), 106 deletions(-) create mode 100644 src/tools/compiletest/src/compute_diff.rs diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs new file mode 100644 index 0000000000000..9ca0c69dbd3e3 --- /dev/null +++ b/src/tools/compiletest/src/compute_diff.rs @@ -0,0 +1,106 @@ +use std::collections::VecDeque; + +#[derive(Debug, PartialEq)] +pub enum DiffLine { + Context(String), + Expected(String), + Resulting(String), +} + +#[derive(Debug, PartialEq)] +pub struct Mismatch { + pub line_number: u32, + pub lines: Vec, +} + +impl Mismatch { + fn new(line_number: u32) -> Mismatch { + Mismatch { line_number, lines: Vec::new() } + } +} + +// Produces a diff between the expected output and actual output. +pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { + let mut line_number = 1; + let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size); + let mut lines_since_mismatch = context_size + 1; + let mut results = Vec::new(); + let mut mismatch = Mismatch::new(0); + + for result in diff::lines(expected, actual) { + match result { + diff::Result::Left(str) => { + if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Expected(str.to_owned())); + line_number += 1; + lines_since_mismatch = 0; + } + diff::Result::Right(str) => { + if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { + results.push(mismatch); + mismatch = Mismatch::new(line_number - context_queue.len() as u32); + } + + while let Some(line) = context_queue.pop_front() { + mismatch.lines.push(DiffLine::Context(line.to_owned())); + } + + mismatch.lines.push(DiffLine::Resulting(str.to_owned())); + lines_since_mismatch = 0; + } + diff::Result::Both(str, _) => { + if context_queue.len() >= context_size { + let _ = context_queue.pop_front(); + } + + if lines_since_mismatch < context_size { + mismatch.lines.push(DiffLine::Context(str.to_owned())); + } else if context_size > 0 { + context_queue.push_back(str); + } + + line_number += 1; + lines_since_mismatch += 1; + } + } + } + + results.push(mismatch); + results.remove(0); + + results +} + +pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> String { + use std::fmt::Write; + let mut output = String::new(); + let diff_results = make_diff(expected, actual, context_size); + for result in diff_results { + let mut line_number = result.line_number; + for line in result.lines { + match line { + DiffLine::Expected(e) => { + writeln!(output, "-\t{}", e).unwrap(); + line_number += 1; + } + DiffLine::Context(c) => { + writeln!(output, "{}\t{}", line_number, c).unwrap(); + line_number += 1; + } + DiffLine::Resulting(r) => { + writeln!(output, "+\t{}", r).unwrap(); + } + } + } + writeln!(output).unwrap(); + } + output +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 9e655557fd271..fbf3249db94d1 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -28,6 +28,7 @@ use self::header::{make_test_description, EarlyProps}; mod tests; pub mod common; +pub mod compute_diff; pub mod errors; pub mod header; mod json; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 2a4bb9eb88b30..ec6c745b7d202 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -8,6 +8,7 @@ use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; use crate::common::{Pretty, RunPassValgrind}; use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; +use crate::compute_diff::write_diff; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; @@ -18,7 +19,7 @@ use regex::{Captures, Regex}; use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; use std::collections::hash_map::DefaultHasher; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, HashSet}; use std::env; use std::ffi::{OsStr, OsString}; use std::fs::{self, create_dir_all, File, OpenOptions}; @@ -100,111 +101,6 @@ pub fn get_lib_name(lib: &str, dylib: bool) -> String { } } -#[derive(Debug, PartialEq)] -pub enum DiffLine { - Context(String), - Expected(String), - Resulting(String), -} - -#[derive(Debug, PartialEq)] -pub struct Mismatch { - pub line_number: u32, - pub lines: Vec, -} - -impl Mismatch { - fn new(line_number: u32) -> Mismatch { - Mismatch { line_number, lines: Vec::new() } - } -} - -// Produces a diff between the expected output and actual output. -pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec { - let mut line_number = 1; - let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size); - let mut lines_since_mismatch = context_size + 1; - let mut results = Vec::new(); - let mut mismatch = Mismatch::new(0); - - for result in diff::lines(expected, actual) { - match result { - diff::Result::Left(str) => { - if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Expected(str.to_owned())); - line_number += 1; - lines_since_mismatch = 0; - } - diff::Result::Right(str) => { - if lines_since_mismatch >= context_size && lines_since_mismatch > 0 { - results.push(mismatch); - mismatch = Mismatch::new(line_number - context_queue.len() as u32); - } - - while let Some(line) = context_queue.pop_front() { - mismatch.lines.push(DiffLine::Context(line.to_owned())); - } - - mismatch.lines.push(DiffLine::Resulting(str.to_owned())); - lines_since_mismatch = 0; - } - diff::Result::Both(str, _) => { - if context_queue.len() >= context_size { - let _ = context_queue.pop_front(); - } - - if lines_since_mismatch < context_size { - mismatch.lines.push(DiffLine::Context(str.to_owned())); - } else if context_size > 0 { - context_queue.push_back(str); - } - - line_number += 1; - lines_since_mismatch += 1; - } - } - } - - results.push(mismatch); - results.remove(0); - - results -} - -fn write_diff(expected: &str, actual: &str, context_size: usize) -> String { - use std::fmt::Write; - let mut output = String::new(); - let diff_results = make_diff(expected, actual, context_size); - for result in diff_results { - let mut line_number = result.line_number; - for line in result.lines { - match line { - DiffLine::Expected(e) => { - writeln!(output, "-\t{}", e).unwrap(); - line_number += 1; - } - DiffLine::Context(c) => { - writeln!(output, "{}\t{}", line_number, c).unwrap(); - line_number += 1; - } - DiffLine::Resulting(r) => { - writeln!(output, "+\t{}", r).unwrap(); - } - } - } - writeln!(output).unwrap(); - } - output -} - pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) { match &*config.target { "arm-linux-androideabi" From 250d1260e6b45b82a07e5f7b28afe983d21fdef3 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sat, 2 Oct 2021 19:00:36 +0800 Subject: [PATCH 04/17] Add `deref_into_dyn_supertrait` lint. --- Cargo.lock | 1 + compiler/rustc_lint_defs/src/builtin.rs | 46 +++++++++++ compiler/rustc_trait_selection/Cargo.toml | 1 + .../src/traits/select/candidate_assembly.rs | 80 ++++++++++++++++++- .../trait-upcasting/migrate-lint-deny.rs | 25 ++++++ .../trait-upcasting/migrate-lint-deny.stderr | 16 ++++ 6 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs create mode 100644 src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr diff --git a/Cargo.lock b/Cargo.lock index a4e1ab6c1e4a8..44dabad28ee7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4457,6 +4457,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_lint_defs", "rustc_macros", "rustc_middle", "rustc_parse_format", diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5830ce26fea3f..afe71fa45582b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3050,6 +3050,7 @@ declare_lint_pass! { BREAK_WITH_LABEL_AND_LOOP, UNUSED_ATTRIBUTES, NON_EXHAUSTIVE_OMITTED_PATTERNS, + DEREF_INTO_DYN_SUPERTRAIT, ] } @@ -3511,3 +3512,48 @@ declare_lint! { Allow, "detect when patterns of types marked `non_exhaustive` are missed", } + +declare_lint! { + /// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the + /// `Deref` implementation with a `dyn SuperTrait` type as `Output`. + /// + /// These implementations will become shadowed when the `trait_upcasting` feature is stablized. + /// The `deref` functions will no longer be called implicitly, so there might be behavior change. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(deref_into_dyn_supertrait)] + /// #![allow(dead_code)] + /// + /// use core::ops::Deref; + /// + /// trait A {} + /// trait B: A {} + /// impl<'a> Deref for dyn 'a + B { + /// type Target = dyn A; + /// fn deref(&self) -> &Self::Target { + /// todo!() + /// } + /// } + /// + /// fn take_a(_: &dyn A) { } + /// + /// fn take_b(b: &dyn B) { + /// take_a(b); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The dyn upcasting coercion feature adds new coercion rules, taking priority + /// over certain other coercion rules, which will cause some behavior change. + pub DEREF_INTO_DYN_SUPERTRAIT, + Warn, + "`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #89460 ", + }; +} diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 9a9737362c6c8..27cd5c2acace4 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -17,6 +17,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } +rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 719412492f637..f3706aa6e71aa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -6,12 +6,17 @@ //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness}; use rustc_target::spec::abi::Abi; +use crate::traits; use crate::traits::coherence::Conflict; +use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{util, SelectionResult}; use crate::traits::{Overflow, Unimplemented}; @@ -672,6 +677,55 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } + /// Temporary migration for #89190 + fn need_migrate_deref_output_trait_object( + &mut self, + ty: Ty<'tcx>, + cause: &traits::ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Option<(Ty<'tcx>, DefId)> { + let tcx = self.tcx(); + if tcx.features().trait_upcasting { + return None; + } + + // + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().deref_trait()?, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let obligation = traits::Obligation::new( + cause.clone(), + param_env, + ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), + ); + if !self.infcx.predicate_may_hold(&obligation) { + return None; + } + + let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot(); + let normalized_ty = fulfillcx.normalize_projection_type( + &self.infcx, + param_env, + ty::ProjectionTy { + item_def_id: tcx.lang_items().deref_target()?, + substs: trait_ref.substs, + }, + cause.clone(), + ); + + let data = if let ty::Dynamic(ref data, ..) = normalized_ty.kind() { + data + } else { + return None; + }; + + let def_id = data.principal_def_id()?; + + return Some((normalized_ty, def_id)); + } + /// Searches for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing( &mut self, @@ -732,6 +786,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let principal_a = data_a.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some((deref_output_ty, deref_output_trait_did)) = self + .need_migrate_deref_output_trait_object( + source, + &obligation.cause, + obligation.param_env, + ) + { + if deref_output_trait_did == target_trait_did { + self.tcx().struct_span_lint_hir( + DEREF_INTO_DYN_SUPERTRAIT, + obligation.cause.body_id, + obligation.cause.span, + |lint| { + lint.build(&format!( + "`{}` implements `Deref` with supertrait `{}` as output", + source, + deref_output_ty + )).emit(); + }, + ); + return; + } + } + for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() { diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs new file mode 100644 index 0000000000000..c6725101858eb --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs @@ -0,0 +1,25 @@ +#![deny(deref_into_dyn_supertrait)] + +extern crate core; + +use core::ops::Deref; + +// issue 89190 +trait A {} +trait B: A {} +impl<'a> Deref for dyn 'a + B { + type Target = dyn A; + fn deref(&self) -> &Self::Target { + todo!() + } +} + +fn take_a(_: &dyn A) {} + +fn whoops(b: &dyn B) { + take_a(b) + //~^ ERROR `dyn B` implements `Deref` with supertrait `(dyn A + 'static)` as output + //~^^ WARN this was previously accepted by the compiler but is being phased out; +} + +fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr new file mode 100644 index 0000000000000..35af9112a27fc --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr @@ -0,0 +1,16 @@ +error: `dyn B` implements `Deref` with supertrait `(dyn A + 'static)` as output + --> $DIR/migrate-lint-deny.rs:20:12 + | +LL | take_a(b) + | ^ + | +note: the lint level is defined here + --> $DIR/migrate-lint-deny.rs:1:9 + | +LL | #![deny(deref_into_dyn_supertrait)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #89460 + +error: aborting due to previous error + From 2a57a462498e3ce954e0b5b7ddd2502bd74875f4 Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sun, 3 Oct 2021 16:53:45 -0700 Subject: [PATCH 05/17] Extract a portion of diff writing code to separate function --- src/tools/compiletest/src/compute_diff.rs | 47 +++++++++++++++++++++++ src/tools/compiletest/src/runtest.rs | 41 ++------------------ 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs index 9ca0c69dbd3e3..fb837a6077a7f 100644 --- a/src/tools/compiletest/src/compute_diff.rs +++ b/src/tools/compiletest/src/compute_diff.rs @@ -1,4 +1,5 @@ use std::collections::VecDeque; +use std::path::Path; #[derive(Debug, PartialEq)] pub enum DiffLine { @@ -104,3 +105,49 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S } output } + +/// Returns whether any data was actually written. +pub(crate) fn write_rustdoc_diff( + diff_filename: &str, + out_dir: &Path, + compare_dir: &Path, + verbose: bool, +) -> bool { + use std::fs::File; + use std::io::{Read, Write}; + let mut diff_output = File::create(diff_filename).unwrap(); + let mut wrote_data = false; + for entry in walkdir::WalkDir::new(out_dir) { + let entry = entry.expect("failed to read file"); + let extension = entry.path().extension().and_then(|p| p.to_str()); + if entry.file_type().is_file() + && (extension == Some("html".into()) || extension == Some("js".into())) + { + let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); + let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; + let actual_path = entry.path(); + let actual = std::fs::read(&actual_path).unwrap(); + let diff = unified_diff::diff( + &expected, + &expected_path.to_string_lossy(), + &actual, + &actual_path.to_string_lossy(), + 3, + ); + wrote_data |= !diff.is_empty(); + diff_output.write_all(&diff).unwrap(); + } + } + + if !wrote_data { + println!("note: diff is identical to nightly rustdoc"); + assert!(diff_output.metadata().unwrap().len() == 0); + return false; + } else if verbose { + eprintln!("printing diff:"); + let mut buf = Vec::new(); + diff_output.read_to_end(&mut buf).unwrap(); + std::io::stderr().lock().write_all(&mut buf).unwrap(); + } + true +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ec6c745b7d202..ffe8f1bb56dfe 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -8,7 +8,7 @@ use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; use crate::common::{Pretty, RunPassValgrind}; use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; -use crate::compute_diff::write_diff; +use crate::compute_diff::{write_diff, write_rustdoc_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; @@ -2403,43 +2403,8 @@ impl<'test> TestCx<'test> { let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id()); - { - let mut diff_output = File::create(&diff_filename).unwrap(); - let mut wrote_data = false; - for entry in walkdir::WalkDir::new(out_dir) { - let entry = entry.expect("failed to read file"); - let extension = entry.path().extension().and_then(|p| p.to_str()); - if entry.file_type().is_file() - && (extension == Some("html".into()) || extension == Some("js".into())) - { - let expected_path = - compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); - let expected = - if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; - let actual_path = entry.path(); - let actual = std::fs::read(&actual_path).unwrap(); - let diff = unified_diff::diff( - &expected, - &expected_path.to_string_lossy(), - &actual, - &actual_path.to_string_lossy(), - 3, - ); - wrote_data |= !diff.is_empty(); - diff_output.write_all(&diff).unwrap(); - } - } - - if !wrote_data { - println!("note: diff is identical to nightly rustdoc"); - assert!(diff_output.metadata().unwrap().len() == 0); - return; - } else if self.config.verbose { - eprintln!("printing diff:"); - let mut buf = Vec::new(); - diff_output.read_to_end(&mut buf).unwrap(); - std::io::stderr().lock().write_all(&mut buf).unwrap(); - } + if !write_rustdoc_diff(&diff_filename, out_dir, &compare_dir, self.config.verbose) { + return; } match self.config.color { From 3760c91252b1a6697fbd05e98e72c7e78493a72e Mon Sep 17 00:00:00 2001 From: Nicholas-Baron Date: Sun, 3 Oct 2021 17:07:43 -0700 Subject: [PATCH 06/17] Make write_rustdoc_diff a more generic function --- src/tools/compiletest/src/compute_diff.rs | 16 ++++++++++------ src/tools/compiletest/src/runtest.rs | 13 +++++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs index fb837a6077a7f..92c80c27de03b 100644 --- a/src/tools/compiletest/src/compute_diff.rs +++ b/src/tools/compiletest/src/compute_diff.rs @@ -1,4 +1,5 @@ use std::collections::VecDeque; +use std::fs::{File, FileType}; use std::path::Path; #[derive(Debug, PartialEq)] @@ -106,23 +107,26 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S output } +/// Filters based on filetype and extension whether to diff a file. +/// /// Returns whether any data was actually written. -pub(crate) fn write_rustdoc_diff( +pub(crate) fn write_filtered_diff( diff_filename: &str, out_dir: &Path, compare_dir: &Path, verbose: bool, -) -> bool { - use std::fs::File; + filter: Filter, +) -> bool +where + Filter: Fn(FileType, Option<&str>) -> bool, +{ use std::io::{Read, Write}; let mut diff_output = File::create(diff_filename).unwrap(); let mut wrote_data = false; for entry in walkdir::WalkDir::new(out_dir) { let entry = entry.expect("failed to read file"); let extension = entry.path().extension().and_then(|p| p.to_str()); - if entry.file_type().is_file() - && (extension == Some("html".into()) || extension == Some("js".into())) - { + if filter(entry.file_type(), extension) { let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap()); let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue }; let actual_path = entry.path(); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ffe8f1bb56dfe..0821e279d2485 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -8,7 +8,7 @@ use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{Config, TestPaths}; use crate::common::{Pretty, RunPassValgrind}; use crate::common::{UI_RUN_STDERR, UI_RUN_STDOUT}; -use crate::compute_diff::{write_diff, write_rustdoc_diff}; +use crate::compute_diff::{write_diff, write_filtered_diff}; use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; @@ -2403,7 +2403,16 @@ impl<'test> TestCx<'test> { let diff_filename = format!("build/tmp/rustdoc-compare-{}.diff", std::process::id()); - if !write_rustdoc_diff(&diff_filename, out_dir, &compare_dir, self.config.verbose) { + if !write_filtered_diff( + &diff_filename, + out_dir, + &compare_dir, + self.config.verbose, + |file_type, extension| { + file_type.is_file() + && (extension == Some("html".into()) || extension == Some("js".into())) + }, + ) { return; } From 67a82e20cfdc6119f65ddfbfa179d0b5426ee753 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Tue, 5 Oct 2021 16:31:36 +0200 Subject: [PATCH 07/17] RustWrapper: adapt for LLVM API change of fatal_error_handler_t No functional changes intended. The LLVM commit https://github.com/llvm/llvm-project/commit/e463b69736da8b0a950ecd937cf990401bdfcdeb changed an argument of fatal_error_handler_t from std::string to char*. This adapts RustWrapper accordingly. --- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9850f395a0f65..97114729c0a27 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -54,7 +54,11 @@ static LLVM_THREAD_LOCAL char *LastError; // // Notably it exits the process with code 101, unlike LLVM's default of 1. static void FatalErrorHandler(void *UserData, +#if LLVM_VERSION_LT(14, 0) const std::string& Reason, +#else + const char* Reason, +#endif bool GenCrashDiag) { // Do the same thing that the default error handler does. std::cerr << "LLVM ERROR: " << Reason << std::endl; From 10cdbd847fd00d093ce89a4fffde5d90c8bb9817 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Tue, 3 Nov 2020 19:45:16 +0100 Subject: [PATCH 08/17] Make cfg implicitly imply doc(cfg) This is only active when the `doc_cfg` feature is active. The implicit cfg can be overridden via #[doc(cfg(...))], so e.g. to hide a #[cfg] you can use something like: ```rust #[cfg(unix)] #[doc(cfg(all()))] pub struct Unix; ``` (since `all()` is always true, it is never shown in the docs) --- src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 52 +++++++++++++++++++++-- src/librustdoc/doctest.rs | 2 +- src/librustdoc/html/render/print_item.rs | 2 +- src/librustdoc/lib.rs | 1 + src/test/rustdoc/doc-cfg-implicit-gate.rs | 7 +++ src/test/rustdoc/doc-cfg-implicit.rs | 31 ++++++++++++++ 8 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 src/test/rustdoc/doc-cfg-implicit-gate.rs create mode 100644 src/test/rustdoc/doc-cfg-implicit.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4a888b22332ee..39493f6edf8c2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -318,10 +318,10 @@ fn merge_attrs( } else { Attributes::from_ast(&both, None) }, - both.cfg(cx.sess()), + both.cfg(cx.tcx), ) } else { - (old_attrs.clean(cx), old_attrs.cfg(cx.sess())) + (old_attrs.clean(cx), old_attrs.cfg(cx.tcx)) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a55d85f5841d2..41bc30fd3989e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1973,7 +1973,7 @@ fn clean_extern_crate( def_id: crate_def_id.into(), visibility: krate.vis.clean(cx), kind: box ExternCrateItem { src: orig_name }, - cfg: attrs.cfg(cx.sess()), + cfg: attrs.cfg(cx.tcx), }] } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0e78fe7aec357..288644ff2969f 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -421,7 +421,7 @@ impl Item { kind, box ast_attrs.clean(cx), cx, - ast_attrs.cfg(cx.sess()), + ast_attrs.cfg(cx.tcx), ) } @@ -747,7 +747,7 @@ crate trait AttributesExt { fn other_attrs(&self) -> Vec; - fn cfg(&self, sess: &Session) -> Option>; + fn cfg(&self, tcx: TyCtxt<'_>) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -772,8 +772,52 @@ impl AttributesExt for [ast::Attribute] { self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() } - fn cfg(&self, sess: &Session) -> Option> { - let mut cfg = Cfg::True; + fn cfg(&self, tcx: TyCtxt<'_>) -> Option> { + let sess = tcx.sess; + let doc_cfg_active = tcx.features().doc_cfg; + + trait SingleExt { + type Item; + fn single(self) -> Option; + } + + impl SingleExt for T { + type Item = T::Item; + fn single(self) -> Option { + let mut iter = self.into_iter(); + let item = iter.next()?; + iter.next().is_none().then_some(())?; + Some(item) + } + } + + let mut cfg = if doc_cfg_active { + let mut doc_cfg = self + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .filter_map(|attr| Some(attr.meta_item_list()?.single()?)) + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone())) + .peekable(); + if doc_cfg.peek().is_some() { + doc_cfg + .filter_map(|attr| { + Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() + }) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } else { + self + .iter() + .filter(|attr| attr.has_name(sym::cfg)) + .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone())) + .filter_map(|attr| { + Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() + }) + .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) + } + } else { + Cfg::True + }; for attr in self.iter() { // #[doc] diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 43abcf095d858..8cf7b50fbd978 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1123,7 +1123,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { let ast_attrs = self.tcx.hir().attrs(hir_id); let mut attrs = Attributes::from_ast(ast_attrs, None); - if let Some(ref cfg) = ast_attrs.cfg(self.sess) { + if let Some(ref cfg) = ast_attrs.cfg(self.tcx) { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 28b2eded7cc3e..e68e122317168 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -323,7 +323,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let import_item = clean::Item { def_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.sess()), + cfg: ast_attrs.cfg(cx.tcx()), ..myitem.clone() }; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index efc8e31498a9c..d070ce22890d2 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -5,6 +5,7 @@ #![feature(rustc_private)] #![feature(array_methods)] #![feature(assert_matches)] +#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(box_syntax)] diff --git a/src/test/rustdoc/doc-cfg-implicit-gate.rs b/src/test/rustdoc/doc-cfg-implicit-gate.rs new file mode 100644 index 0000000000000..92804d3729bba --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit-gate.rs @@ -0,0 +1,7 @@ +// compile-flags:--cfg feature="worricow" +#![crate_name = "xenogenous"] + +// @has 'xenogenous/struct.Worricow.html' +// @count - '//*[@class="stab portability"]' 0 +#[cfg(feature = "worricow")] +pub struct Worricow; diff --git a/src/test/rustdoc/doc-cfg-implicit.rs b/src/test/rustdoc/doc-cfg-implicit.rs new file mode 100644 index 0000000000000..36c2025785d0f --- /dev/null +++ b/src/test/rustdoc/doc-cfg-implicit.rs @@ -0,0 +1,31 @@ +#![crate_name = "funambulism"] +#![feature(doc_cfg)] + +// @has 'funambulism/struct.Disorbed.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature disorbed' +// compile-flags:--cfg feature="disorbed" +#[cfg(feature = "disorbed")] +pub struct Disorbed; + +// @has 'funambulism/struct.Aesthesia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature aesthesia' +// compile-flags:--cfg feature="aesthesia" +#[doc(cfg(feature = "aesthesia"))] +pub struct Aesthesia; + +// @has 'funambulism/struct.Pliothermic.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature pliothermic' +// compile-flags:--cfg feature="epopoeist" +#[cfg(feature = "epopoeist")] +#[doc(cfg(feature = "pliothermic"))] +pub struct Pliothermic; + +// @has 'funambulism/struct.Simillimum.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="simillimum" +#[cfg(feature = "simillimum")] +#[doc(cfg(all()))] +pub struct Simillimum; From 18fdd816b72cbf1547efbb81f164f7a457f17b78 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Wed, 4 Nov 2020 21:59:35 +0100 Subject: [PATCH 09/17] Allow adding a set of cfg's to hide from being implicitly doc(cfg)'d By adding #![doc(cfg_hide(foobar))] to the crate attributes the cfg #[cfg(foobar)] (and _only_ that _exact_ cfg) will not be implicitly treated as a doc(cfg) to render a message in the documentation. --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/active.rs | 3 ++ compiler/rustc_span/src/symbol.rs | 2 ++ src/librustdoc/clean/inline.rs | 4 +-- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 9 ++++-- src/librustdoc/doctest.rs | 2 +- src/librustdoc/formats/cache.rs | 2 ++ src/librustdoc/html/render/print_item.rs | 2 +- src/librustdoc/visit_ast.rs | 24 +++++++++++++- src/test/rustdoc/doc-cfg-hide.rs | 32 +++++++++++++++++++ 11 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 src/test/rustdoc/doc-cfg-hide.rs diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 06e9d9ed32933..bce5cd8174d08 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -279,6 +279,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_doc!( cfg => doc_cfg + cfg_hide => doc_cfg_hide masked => doc_masked notable_trait => doc_notable_trait keyword => doc_keyword diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index eae7f7854ecb1..e5c57d0ee3023 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -380,6 +380,9 @@ declare_features! ( /// Allows `#[doc(cfg(...))]`. (active, doc_cfg, "1.21.0", Some(43781), None), + /// Allows `#[doc(cfg_hide(...))]`. + (active, doc_cfg_hide, "1.49.0", Some(43781), None), + /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 77baf7d73810e..382dbc377d63e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -399,6 +399,7 @@ symbols! { cfg_attr_multi, cfg_doctest, cfg_eval, + cfg_hide, cfg_panic, cfg_sanitize, cfg_target_abi, @@ -547,6 +548,7 @@ symbols! { doc, doc_alias, doc_cfg, + doc_cfg_hide, doc_keyword, doc_masked, doc_notable_trait, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 39493f6edf8c2..b463c1dc7146b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -318,10 +318,10 @@ fn merge_attrs( } else { Attributes::from_ast(&both, None) }, - both.cfg(cx.tcx), + both.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } else { - (old_attrs.clean(cx), old_attrs.cfg(cx.tcx)) + (old_attrs.clean(cx), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 41bc30fd3989e..969d15dd6a160 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1973,7 +1973,7 @@ fn clean_extern_crate( def_id: crate_def_id.into(), visibility: krate.vis.clean(cx), kind: box ExternCrateItem { src: orig_name }, - cfg: attrs.cfg(cx.tcx), + cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), }] } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 288644ff2969f..ebbf280d96d29 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -421,7 +421,7 @@ impl Item { kind, box ast_attrs.clean(cx), cx, - ast_attrs.cfg(cx.tcx), + ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), ) } @@ -747,7 +747,7 @@ crate trait AttributesExt { fn other_attrs(&self) -> Vec; - fn cfg(&self, tcx: TyCtxt<'_>) -> Option>; + fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -772,7 +772,7 @@ impl AttributesExt for [ast::Attribute] { self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() } - fn cfg(&self, tcx: TyCtxt<'_>) -> Option> { + fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet) -> Option> { let sess = tcx.sess; let doc_cfg_active = tcx.features().doc_cfg; @@ -813,6 +813,7 @@ impl AttributesExt for [ast::Attribute] { .filter_map(|attr| { Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() }) + .filter(|cfg| !hidden_cfg.contains(cfg)) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } } else { @@ -844,6 +845,8 @@ impl AttributesExt for [ast::Attribute] { } } + // treat #[target_feature(enable = "feat")] attributes as if they were + // #[doc(cfg(target_feature = "feat"))] attributes as well for attr in self.lists(sym::target_feature) { if attr.has_name(sym::enable) { if let Some(feat) = attr.value_str() { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 8cf7b50fbd978..9e64d200b4373 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1123,7 +1123,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { let ast_attrs = self.tcx.hir().attrs(hir_id); let mut attrs = Attributes::from_ast(ast_attrs, None); - if let Some(ref cfg) = ast_attrs.cfg(self.tcx) { + if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index bcfcc3d70395c..cc9e081add199 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -119,6 +119,8 @@ crate struct Cache { /// /// Links are indexed by the DefId of the item they document. crate intra_doc_links: FxHashMap>, + /// Cfg that have been hidden via #![doc(cfg_hide(...))] + crate hidden_cfg: FxHashSet, } /// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`. diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e68e122317168..e3ffc1e3f21f3 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -323,7 +323,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let import_item = clean::Item { def_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.tcx()), + cfg: ast_attrs.cfg(cx.tcx(), &cx.cache().hidden_cfg), ..myitem.clone() }; diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4f5495a176dfc..cd657fa01d453 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; +use rustc_hir::CRATE_HIR_ID; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::Node; @@ -15,7 +16,7 @@ use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; -use crate::clean::{self, AttributesExt, NestedAttributesExt}; +use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt}; use crate::core; use crate::doctree::*; @@ -97,6 +98,27 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } } + + self.cx.cache.hidden_cfg = self.cx.tcx.hir().attrs(CRATE_HIR_ID) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) + .filter(|attr| attr.has_name(sym::cfg_hide)) + .flat_map(|attr| { + attr.meta_item_list() + .unwrap_or(&[]) + .iter() + .filter_map(|attr| { + Some( + Cfg::parse(attr.meta_item()?) + .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg)) + .ok()?, + ) + }) + .collect::>() + }) + .collect(); + self.cx.cache.exact_paths = self.exact_paths; top_level_module } diff --git a/src/test/rustdoc/doc-cfg-hide.rs b/src/test/rustdoc/doc-cfg-hide.rs new file mode 100644 index 0000000000000..b9d0d32313723 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-hide.rs @@ -0,0 +1,32 @@ +#![crate_name = "oud"] +#![feature(doc_cfg, doc_cfg_hide)] + +#![doc(cfg_hide(feature = "solecism"))] + +// @has 'oud/struct.Solecism.html' +// @count - '//*[@class="stab portability"]' 0 +// compile-flags:--cfg feature="solecism" +#[cfg(feature = "solecism")] +pub struct Solecism; + +// @has 'oud/struct.Scribacious.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature solecism' +#[cfg(feature = "solecism")] +#[doc(cfg(feature = "solecism"))] +pub struct Scribacious; + +// @has 'oud/struct.Hyperdulia.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate feature hyperdulia' +// compile-flags:--cfg feature="hyperdulia" +#[cfg(feature = "solecism")] +#[cfg(feature = "hyperdulia")] +pub struct Hyperdulia; + +// @has 'oud/struct.Oystercatcher.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' 'crate features solecism and oystercatcher' +// compile-flags:--cfg feature="oystercatcher" +#[cfg(all(feature = "solecism", feature = "oystercatcher"))] +pub struct Oystercatcher; From 0031ce3a91d8e00691d09fcfca3164bc906f69af Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Wed, 4 Nov 2020 22:58:37 +0100 Subject: [PATCH 10/17] Suppress some cfg from being shown in the stdlib docs --- library/alloc/src/lib.rs | 7 ++++++- library/core/src/lib.rs | 26 +++++++++++++++++++++++++- library/std/src/lib.rs | 6 +++++- library/std/src/os/raw/mod.rs | 6 ++++++ library/std/src/os/windows/raw.rs | 2 ++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ca41ce975e4fe..a9704bed2df67 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -65,7 +65,10 @@ #![doc( html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) + test(no_crate_inject, attr(allow(unused_variables), deny(warnings))), +)] +#![cfg_attr(not(bootstrap), + doc(cfg_hide(not(test), not(any(test, bootstrap)), target_has_atomic = "ptr")) )] #![no_std] #![needs_allocator] @@ -146,6 +149,8 @@ #![feature(associated_type_bounds)] #![feature(slice_group_by)] #![feature(decl_macro)] +#![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] // Allow testing this library #[cfg(test)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 4742970f9542b..f4670d8feb233 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -58,7 +58,30 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))), +)] +#![cfg_attr(not(bootstrap), + doc(cfg_hide( + not(test), + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64", + target_has_atomic = "8", + target_has_atomic = "16", + target_has_atomic = "32", + target_has_atomic = "64", + target_has_atomic = "ptr", + target_has_atomic_equal_alignment = "8", + target_has_atomic_equal_alignment = "16", + target_has_atomic_equal_alignment = "32", + target_has_atomic_equal_alignment = "64", + target_has_atomic_equal_alignment = "ptr", + target_has_atomic_load_store = "8", + target_has_atomic_load_store = "16", + target_has_atomic_load_store = "32", + target_has_atomic_load_store = "64", + target_has_atomic_load_store = "ptr", + )) )] #![no_core] // @@ -133,6 +156,7 @@ #![feature(doc_notable_trait)] #![feature(doc_primitive)] #![feature(exhaustive_patterns)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![feature(extern_types)] #![feature(fundamental)] #![feature(if_let_guard)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0ba4e85886caa..af48e5e9bd297 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -193,7 +193,10 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))), +)] +#![cfg_attr(not(bootstrap), + doc(cfg_hide(not(test), not(any(test, bootstrap)))) )] // Don't link to std. We are std. #![no_std] @@ -263,6 +266,7 @@ #![feature(custom_test_frameworks)] #![feature(decl_macro)] #![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))] #![feature(doc_keyword)] #![feature(doc_masked)] #![feature(doc_notable_trait)] diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 1e220ea30ab95..30eeac14b43f5 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -46,6 +46,7 @@ macro_rules! type_alias { } type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; +#[doc(cfg(all()))] #[cfg(any( all( target_os = "linux", @@ -88,6 +89,7 @@ type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; all(target_os = "fuchsia", target_arch = "aarch64") ))]} type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8; +#[doc(cfg(all()))] #[cfg(not(any( all( target_os = "linux", @@ -136,12 +138,16 @@ type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; } type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; } type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; } type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32; +#[doc(cfg(all()))] #[cfg(any(target_pointer_width = "32", windows))] } type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64; +#[doc(cfg(all()))] #[cfg(all(target_pointer_width = "64", not(windows)))] } type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } diff --git a/library/std/src/os/windows/raw.rs b/library/std/src/os/windows/raw.rs index 5014e008eb599..0ef3adade5c83 100644 --- a/library/std/src/os/windows/raw.rs +++ b/library/std/src/os/windows/raw.rs @@ -7,8 +7,10 @@ use crate::os::raw::c_void; #[stable(feature = "raw_ext", since = "1.1.0")] pub type HANDLE = *mut c_void; #[cfg(target_pointer_width = "32")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u32; #[cfg(target_pointer_width = "64")] +#[doc(cfg(all()))] #[stable(feature = "raw_ext", since = "1.1.0")] pub type SOCKET = u64; From e36a370f08c14ffa2e9663b8af036aca93c9bf2b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 23 Feb 2021 22:32:33 -0500 Subject: [PATCH 11/17] Add test case for `doc_cfg_hide` feature gate --- compiler/rustc_feature/src/active.rs | 6 +++--- src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs | 7 +++++++ .../rustdoc-ui/feature-gate-doc_cfg_hide.stderr | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs create mode 100644 src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index e5c57d0ee3023..fd6e631c2b577 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -380,9 +380,6 @@ declare_features! ( /// Allows `#[doc(cfg(...))]`. (active, doc_cfg, "1.21.0", Some(43781), None), - /// Allows `#[doc(cfg_hide(...))]`. - (active, doc_cfg_hide, "1.49.0", Some(43781), None), - /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), @@ -678,6 +675,9 @@ declare_features! ( /// Allows `#[track_caller]` on closures and generators. (active, closure_track_caller, "1.57.0", Some(87417), None), + /// Allows `#[doc(cfg_hide(...))]`. + (active, doc_cfg_hide, "1.53.0", Some(43781), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs new file mode 100644 index 0000000000000..17812018b9b7a --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.rs @@ -0,0 +1,7 @@ +#![doc(cfg_hide(test))] +//~^ ERROR `#[doc(cfg_hide)]` is experimental + +#[cfg(not(test))] +pub fn public_fn() {} +#[cfg(test)] +pub fn internal_use_only() {} diff --git a/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr new file mode 100644 index 0000000000000..ba42c7bbb05bc --- /dev/null +++ b/src/test/rustdoc-ui/feature-gate-doc_cfg_hide.stderr @@ -0,0 +1,14 @@ +error[E0658]: `#[doc(cfg_hide)]` is experimental + --> $DIR/feature-gate-doc_cfg_hide.rs:1:1 + | +LL | #![doc(cfg_hide(test))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #43781 for more information + = help: add `#![feature(doc_cfg_hide)]` to the crate attributes to enable + +error: Compilation failed, aborting rustdoc + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 56e5f614947c7f9ddde17c579e2e17b39260b17d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 23 Apr 2021 10:52:38 -0400 Subject: [PATCH 12/17] Add `cfg_hide` to the list of known attributes --- compiler/rustc_passes/src/check_attr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3e59fc4f55159..8d3c2bb1c7b9b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -908,6 +908,7 @@ impl CheckAttrVisitor<'tcx> { // plugins: removed, but rustdoc warns about it itself sym::alias | sym::cfg + | sym::cfg_hide | sym::hidden | sym::html_favicon_url | sym::html_logo_url From a15879d662f2cdc5ff509bb53a032bce818cf3a6 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 6 Oct 2021 01:51:51 +0100 Subject: [PATCH 13/17] Emit item no type error even if type inference fails --- compiler/rustc_typeck/src/collect/type_of.rs | 44 ++++++++++---------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 2e607de1d3371..cee3679d0a052 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -752,29 +752,31 @@ fn infer_placeholder_type<'a>( // us to improve in typeck so we do that now. match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) { Some(mut err) => { - // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. - // We are typeck and have the real type, so remove that and suggest the actual type. - err.suggestions.clear(); - - // Suggesting unnameable types won't help. - let mut mk_nameable = MakeNameable::new(tcx); - let ty = mk_nameable.fold_ty(ty); - let sugg_ty = if mk_nameable.success { Some(ty) } else { None }; - if let Some(sugg_ty) = sugg_ty { - err.span_suggestion( - span, - &format!("provide a type for the {item}", item = kind), - format!("{}: {}", item_ident, sugg_ty), - Applicability::MachineApplicable, - ); - } else { - err.span_note( - tcx.hir().body(body_id).value.span, - &format!("however, the inferred type `{}` cannot be named", ty.to_string()), - ); + if !ty.references_error() { + // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. + // We are typeck and have the real type, so remove that and suggest the actual type. + err.suggestions.clear(); + + // Suggesting unnameable types won't help. + let mut mk_nameable = MakeNameable::new(tcx); + let ty = mk_nameable.fold_ty(ty); + let sugg_ty = if mk_nameable.success { Some(ty) } else { None }; + if let Some(sugg_ty) = sugg_ty { + err.span_suggestion( + span, + &format!("provide a type for the {item}", item = kind), + format!("{}: {}", item_ident, sugg_ty), + Applicability::MachineApplicable, + ); + } else { + err.span_note( + tcx.hir().body(body_id).value.span, + &format!("however, the inferred type `{}` cannot be named", ty.to_string()), + ); + } } - err.emit_unless(ty.references_error()); + err.emit(); } None => { let mut diag = bad_placeholder_type(tcx, vec![span], kind); From b4c62d5f2c0cec1b5332dbbf843b4134ad8123ae Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 6 Oct 2021 01:52:45 +0100 Subject: [PATCH 14/17] Add regression test for ice 89574 --- src/test/ui/parser/issue-89574.rs | 4 ++++ src/test/ui/parser/issue-89574.stderr | 8 ++++++++ .../item-free-const-no-body-semantic-fail.rs | 1 + ...tem-free-const-no-body-semantic-fail.stderr | 8 +++++++- .../item-free-static-no-body-semantic-fail.rs | 2 ++ ...em-free-static-no-body-semantic-fail.stderr | 18 +++++++++++++++--- src/test/ui/typeck/issue-79040.rs | 2 +- src/test/ui/typeck/issue-79040.stderr | 8 +++----- 8 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/parser/issue-89574.rs create mode 100644 src/test/ui/parser/issue-89574.stderr diff --git a/src/test/ui/parser/issue-89574.rs b/src/test/ui/parser/issue-89574.rs new file mode 100644 index 0000000000000..0a477f1aa5fb6 --- /dev/null +++ b/src/test/ui/parser/issue-89574.rs @@ -0,0 +1,4 @@ +fn main() { + const EMPTY_ARRAY = []; + //~^ missing type for `const` item +} diff --git a/src/test/ui/parser/issue-89574.stderr b/src/test/ui/parser/issue-89574.stderr new file mode 100644 index 0000000000000..cbee3d35155c7 --- /dev/null +++ b/src/test/ui/parser/issue-89574.stderr @@ -0,0 +1,8 @@ +error: missing type for `const` item + --> $DIR/issue-89574.rs:2:11 + | +LL | const EMPTY_ARRAY = []; + | ^^^^^^^^^^^ help: provide a type for the item: `EMPTY_ARRAY: ` + +error: aborting due to previous error + diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs index 15a15a207b1ca..613b3c9856171 100644 --- a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs @@ -4,3 +4,4 @@ fn main() {} const A: u8; //~ ERROR free constant item without body const B; //~ ERROR free constant item without body +//~^ ERROR missing type for `const` item diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr index aa75e5cee01d4..c340e958ee585 100644 --- a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -14,5 +14,11 @@ LL | const B; | | | help: provide a definition for the constant: `= ;` -error: aborting due to 2 previous errors +error: missing type for `const` item + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7 + | +LL | const B; + | ^ help: provide a type for the item: `B: ` + +error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs index 61d3eab24d8c7..780479e3d26ac 100644 --- a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs @@ -4,6 +4,8 @@ fn main() {} static A: u8; //~ ERROR free static item without body static B; //~ ERROR free static item without body +//~^ ERROR missing type for `static` item static mut C: u8; //~ ERROR free static item without body static mut D; //~ ERROR free static item without body +//~^ ERROR missing type for `static mut` item diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr index 7b408323674de..4d542b79861fd 100644 --- a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr @@ -15,7 +15,7 @@ LL | static B; | help: provide a definition for the static: `= ;` error: free static item without body - --> $DIR/item-free-static-no-body-semantic-fail.rs:8:1 + --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1 | LL | static mut C: u8; | ^^^^^^^^^^^^^^^^- @@ -23,12 +23,24 @@ LL | static mut C: u8; | help: provide a definition for the static: `= ;` error: free static item without body - --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1 + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:1 | LL | static mut D; | ^^^^^^^^^^^^- | | | help: provide a definition for the static: `= ;` -error: aborting due to 4 previous errors +error: missing type for `static` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8 + | +LL | static B; + | ^ help: provide a type for the item: `B: ` + +error: missing type for `static mut` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12 + | +LL | static mut D; + | ^ help: provide a type for the item: `D: ` + +error: aborting due to 6 previous errors diff --git a/src/test/ui/typeck/issue-79040.rs b/src/test/ui/typeck/issue-79040.rs index af2a9c1ba87ef..941612542207c 100644 --- a/src/test/ui/typeck/issue-79040.rs +++ b/src/test/ui/typeck/issue-79040.rs @@ -1,5 +1,5 @@ fn main() { const FOO = "hello" + 1; //~ ERROR cannot add `{integer}` to `&str` - //~^ ERROR cannot add `{integer}` to `&str` + //~^ missing type for `const` item println!("{}", FOO); } diff --git a/src/test/ui/typeck/issue-79040.stderr b/src/test/ui/typeck/issue-79040.stderr index 32049e5d96860..aec2e1ec9e4ef 100644 --- a/src/test/ui/typeck/issue-79040.stderr +++ b/src/test/ui/typeck/issue-79040.stderr @@ -6,13 +6,11 @@ LL | const FOO = "hello" + 1; | | | &str -error[E0369]: cannot add `{integer}` to `&str` - --> $DIR/issue-79040.rs:2:25 +error: missing type for `const` item + --> $DIR/issue-79040.rs:2:11 | LL | const FOO = "hello" + 1; - | ------- ^ - {integer} - | | - | &str + | ^^^ help: provide a type for the item: `FOO: ` error: aborting due to 2 previous errors From 8fac41a530d3add62464292066130c266a303258 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Oct 2021 15:34:59 +0200 Subject: [PATCH 15/17] Clean up code a bit: * Remove "bool_to_options" feature * Update version for compiler feature * rustfmt --- compiler/rustc_feature/src/active.rs | 2 +- library/alloc/src/lib.rs | 5 +++-- library/core/src/lib.rs | 5 +++-- library/std/src/lib.rs | 6 ++---- src/librustdoc/clean/types.rs | 15 ++++++++++----- src/librustdoc/lib.rs | 1 - src/librustdoc/visit_ast.rs | 8 ++++++-- 7 files changed, 25 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index fd6e631c2b577..ec2c703ad495d 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -676,7 +676,7 @@ declare_features! ( (active, closure_track_caller, "1.57.0", Some(87417), None), /// Allows `#[doc(cfg_hide(...))]`. - (active, doc_cfg_hide, "1.53.0", Some(43781), None), + (active, doc_cfg_hide, "1.57.0", Some(43781), None), // ------------------------------------------------------------------------- // feature-group-end: actual feature gates diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index a9704bed2df67..72fe84222deac 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -65,9 +65,10 @@ #![doc( html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(allow(unused_variables), deny(warnings))), + test(no_crate_inject, attr(allow(unused_variables), deny(warnings))) )] -#![cfg_attr(not(bootstrap), +#![cfg_attr( + not(bootstrap), doc(cfg_hide(not(test), not(any(test, bootstrap)), target_has_atomic = "ptr")) )] #![no_std] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f4670d8feb233..630cf31634ac9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -58,9 +58,10 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))), + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] -#![cfg_attr(not(bootstrap), +#![cfg_attr( + not(bootstrap), doc(cfg_hide( not(test), target_pointer_width = "16", diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index af48e5e9bd297..e074609773a7b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -193,11 +193,9 @@ html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), - test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))), -)] -#![cfg_attr(not(bootstrap), - doc(cfg_hide(not(test), not(any(test, bootstrap)))) + test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr(not(bootstrap), doc(cfg_hide(not(test), not(any(test, bootstrap)))))] // Don't link to std. We are std. #![no_std] #![warn(deprecated_in_future)] diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ebbf280d96d29..09cb99dbf223d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -786,7 +786,9 @@ impl AttributesExt for [ast::Attribute] { fn single(self) -> Option { let mut iter = self.into_iter(); let item = iter.next()?; - iter.next().is_none().then_some(())?; + if iter.next().is_some() { + return None; + } Some(item) } } @@ -802,16 +804,19 @@ impl AttributesExt for [ast::Attribute] { if doc_cfg.peek().is_some() { doc_cfg .filter_map(|attr| { - Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() + Cfg::parse(&attr) + .map_err(|e| sess.diagnostic().span_err(e.span, e.msg)) + .ok() }) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else { - self - .iter() + self.iter() .filter(|attr| attr.has_name(sym::cfg)) .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone())) .filter_map(|attr| { - Cfg::parse(&attr).map_err(|e| sess.diagnostic().span_err(e.span, e.msg)).ok() + Cfg::parse(&attr) + .map_err(|e| sess.diagnostic().span_err(e.span, e.msg)) + .ok() }) .filter(|cfg| !hidden_cfg.contains(cfg)) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index d070ce22890d2..efc8e31498a9c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -5,7 +5,6 @@ #![feature(rustc_private)] #![feature(array_methods)] #![feature(assert_matches)] -#![feature(bool_to_option)] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(box_syntax)] diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index cd657fa01d453..36b1a14f6c1ea 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -3,10 +3,10 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; -use rustc_hir::CRATE_HIR_ID; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::Node; +use rustc_hir::CRATE_HIR_ID; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span; @@ -99,7 +99,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - self.cx.cache.hidden_cfg = self.cx.tcx.hir().attrs(CRATE_HIR_ID) + self.cx.cache.hidden_cfg = self + .cx + .tcx + .hir() + .attrs(CRATE_HIR_ID) .iter() .filter(|attr| attr.has_name(sym::doc)) .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) From 09c76884bc6ba1957dc6d71d79b797de2cc40b2d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 6 Oct 2021 20:06:33 +0200 Subject: [PATCH 16/17] Simplify AttributesExt::cfg function and remove error emissions since they are not useful --- src/librustdoc/clean/types.rs | 37 ++++++++---------------------- src/test/rustdoc-ui/doc-cfg.rs | 9 ++++++++ src/test/rustdoc-ui/doc-cfg.stderr | 26 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 27 deletions(-) create mode 100644 src/test/rustdoc-ui/doc-cfg.rs create mode 100644 src/test/rustdoc-ui/doc-cfg.stderr diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 09cb99dbf223d..5b722175f988c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -776,48 +776,31 @@ impl AttributesExt for [ast::Attribute] { let sess = tcx.sess; let doc_cfg_active = tcx.features().doc_cfg; - trait SingleExt { - type Item; - fn single(self) -> Option; - } - - impl SingleExt for T { - type Item = T::Item; - fn single(self) -> Option { - let mut iter = self.into_iter(); - let item = iter.next()?; - if iter.next().is_some() { - return None; - } - Some(item) + fn single(it: T) -> Option { + let mut iter = it.into_iter(); + let item = iter.next()?; + if iter.next().is_some() { + return None; } + Some(item) } let mut cfg = if doc_cfg_active { let mut doc_cfg = self .iter() .filter(|attr| attr.has_name(sym::doc)) - .filter_map(|attr| Some(attr.meta_item_list()?.single()?)) + .flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new)) .filter(|attr| attr.has_name(sym::cfg)) - .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone())) .peekable(); if doc_cfg.peek().is_some() { doc_cfg - .filter_map(|attr| { - Cfg::parse(&attr) - .map_err(|e| sess.diagnostic().span_err(e.span, e.msg)) - .ok() - }) + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } else { self.iter() .filter(|attr| attr.has_name(sym::cfg)) - .filter_map(|attr| Some(attr.meta_item_list()?.single()?.meta_item()?.clone())) - .filter_map(|attr| { - Cfg::parse(&attr) - .map_err(|e| sess.diagnostic().span_err(e.span, e.msg)) - .ok() - }) + .filter_map(|attr| single(attr.meta_item_list()?)) + .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok()) .filter(|cfg| !hidden_cfg.contains(cfg)) .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg) } diff --git a/src/test/rustdoc-ui/doc-cfg.rs b/src/test/rustdoc-ui/doc-cfg.rs new file mode 100644 index 0000000000000..354d76bc3c433 --- /dev/null +++ b/src/test/rustdoc-ui/doc-cfg.rs @@ -0,0 +1,9 @@ +#![feature(doc_cfg)] + +#[doc(cfg(), cfg(foo, bar))] +//~^ ERROR +//~^^ ERROR +#[doc(cfg(foo), cfg(bar))] // ok! +#[doc(cfg())] //~ ERROR +#[doc(cfg(foo, bar))] //~ ERROR +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc-cfg.stderr b/src/test/rustdoc-ui/doc-cfg.stderr new file mode 100644 index 0000000000000..b379f6febe29f --- /dev/null +++ b/src/test/rustdoc-ui/doc-cfg.stderr @@ -0,0 +1,26 @@ +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:3:7 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:3:23 + | +LL | #[doc(cfg(), cfg(foo, bar))] + | ^^^ + +error: `cfg` predicate is not specified + --> $DIR/doc-cfg.rs:7:7 + | +LL | #[doc(cfg())] + | ^^^^^ + +error: multiple `cfg` predicates are specified + --> $DIR/doc-cfg.rs:8:16 + | +LL | #[doc(cfg(foo, bar))] + | ^^^ + +error: aborting due to 4 previous errors + From 549a68b73e4839e8a8d4d3a427a6ccb72f6d164c Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Wed, 6 Oct 2021 19:07:56 -0700 Subject: [PATCH 17/17] Add InferCtxt::with_opaque_type_inference to get_body_with_borrowck_facts --- compiler/rustc_borrowck/src/consumers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 4333038a6f936..97daad201d959 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -31,7 +31,7 @@ pub fn get_body_with_borrowck_facts<'tcx>( def: ty::WithOptConstParam, ) -> BodyWithBorrowckFacts<'tcx> { let (input_body, promoted) = tcx.mir_promoted(def); - tcx.infer_ctxt().enter(|infcx| { + tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| { let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexVec<_, _> = &promoted.borrow(); *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()