Auto merge of #89629 - GuillaumeGomez:rollup-s4r8me6, r=GuillaumeGomez

Rollup of 7 pull requests

Successful merges:

 - #89298 (Issue 89193 - Fix ICE when using `usize` and `isize` with SIMD gathers )
 - #89461 (Add `deref_into_dyn_supertrait` lint.)
 - #89477 (Move items related to computing diffs to a separate file)
 - #89559 (RustWrapper: adapt for LLVM API change)
 - #89585 (Emit item no type error even if type inference fails)
 - #89596 (Make cfg imply doc(cfg))
 - #89615 (Add InferCtxt::with_opaque_type_inference to get_body_with_borrowck_facts)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2021-10-07 17:17:25 +00:00
commit 5641481ad7
45 changed files with 729 additions and 192 deletions

View File

@ -4454,6 +4454,7 @@ dependencies = [
"rustc_hir",
"rustc_index",
"rustc_infer",
"rustc_lint_defs",
"rustc_macros",
"rustc_middle",
"rustc_parse_format",

View File

@ -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

View File

@ -31,7 +31,7 @@ pub fn get_body_with_borrowck_facts<'tcx>(
def: ty::WithOptConstParam<LocalDefId>,
) -> 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()

View File

@ -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;
@ -1190,11 +1190,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!(),
}
@ -1330,11 +1347,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);
@ -1458,11 +1475,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);

View File

@ -675,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.57.0", Some(43781), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------

View File

@ -3051,6 +3051,7 @@ declare_lint_pass! {
BREAK_WITH_LABEL_AND_LOOP,
UNUSED_ATTRIBUTES,
NON_EXHAUSTIVE_OMITTED_PATTERNS,
DEREF_INTO_DYN_SUPERTRAIT,
]
}
@ -3512,3 +3513,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 <https://github.com/rust-lang/rust/issues/89460>",
};
}

View File

@ -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;

View File

@ -938,6 +938,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

View File

@ -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,

View File

@ -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_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }

View File

@ -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;
}
// <ty as Deref>
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()
{

View File

@ -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();
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()),
);
// 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);

View File

@ -67,6 +67,10 @@
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
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]
#![warn(deprecated_in_future)]
@ -146,6 +150,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)]

View File

@ -60,6 +60,30 @@
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),
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]
//
// Lints:
@ -133,6 +157,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)]

View File

@ -195,6 +195,7 @@
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)))))]
// Don't link to std. We are std.
#![no_std]
#![warn(deprecated_in_future)]
@ -263,6 +264,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)]

View File

@ -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; }

View File

@ -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;

View File

@ -318,10 +318,10 @@ fn merge_attrs(
} else {
Attributes::from_ast(&both, None)
},
both.cfg(cx.sess()),
both.cfg(cx.tcx, &cx.cache.hidden_cfg),
)
} else {
(old_attrs.clean(cx), old_attrs.cfg(cx.sess()))
(old_attrs.clean(cx), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
}
}

View File

@ -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, &cx.cache.hidden_cfg),
}]
}

View File

@ -421,7 +421,7 @@ impl Item {
kind,
box ast_attrs.clean(cx),
cx,
ast_attrs.cfg(cx.sess()),
ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
)
}
@ -747,7 +747,7 @@ crate trait AttributesExt {
fn other_attrs(&self) -> Vec<ast::Attribute>;
fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>>;
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>>;
}
impl AttributesExt for [ast::Attribute] {
@ -772,8 +772,41 @@ impl AttributesExt for [ast::Attribute] {
self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
}
fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>> {
let mut cfg = Cfg::True;
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
let sess = tcx.sess;
let doc_cfg_active = tcx.features().doc_cfg;
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
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))
.flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new))
.filter(|attr| attr.has_name(sym::cfg))
.peekable();
if doc_cfg.peek().is_some() {
doc_cfg
.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| 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)
}
} else {
Cfg::True
};
for attr in self.iter() {
// #[doc]
@ -800,6 +833,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() {

View File

@ -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, &FxHashSet::default()) {
if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
return;
}

View File

@ -119,6 +119,8 @@ crate struct Cache {
///
/// Links are indexed by the DefId of the item they document.
crate intra_doc_links: FxHashMap<ItemId, Vec<clean::ItemLink>>,
/// Cfg that have been hidden via #![doc(cfg_hide(...))]
crate hidden_cfg: FxHashSet<clean::cfg::Cfg>,
}
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.

View File

@ -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(), &cx.cache().hidden_cfg),
..myitem.clone()
};

View File

@ -6,6 +6,7 @@ use rustc_hir as hir;
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;
@ -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,31 @@ 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::<Vec<_>>()
})
.collect();
self.cx.cache.exact_paths = self.exact_paths;
top_level_module
}

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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 <https://github.com/rust-lang/rust/issues/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`.

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,4 @@
fn main() {
const EMPTY_ARRAY = [];
//~^ missing type for `const` item
}

View File

@ -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: <type>`
error: aborting due to previous error

View File

@ -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

View File

@ -14,5 +14,11 @@ LL | const B;
| |
| help: provide a definition for the constant: `= <expr>;`
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: <type>`
error: aborting due to 3 previous errors

View File

@ -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

View File

@ -15,7 +15,7 @@ LL | static B;
| help: provide a definition for the static: `= <expr>;`
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: `= <expr>;`
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: `= <expr>;`
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: <type>`
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: <type>`
error: aborting due to 6 previous errors

View File

@ -0,0 +1,51 @@
// 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<T>(pub T, pub T, pub T, pub T);
extern "platform-intrinsic" {
fn simd_gather<T, U, V>(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);
}
}

View File

@ -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() {}

View File

@ -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 <https://github.com/rust-lang/rust/issues/89460>
error: aborting due to previous error

View File

@ -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);
}

View File

@ -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: <type>`
error: aborting due to 2 previous errors

View File

@ -0,0 +1,157 @@
use std::collections::VecDeque;
use std::fs::{File, FileType};
use std::path::Path;
#[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<DiffLine>,
}
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<Mismatch> {
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
}
/// Filters based on filetype and extension whether to diff a file.
///
/// Returns whether any data was actually written.
pub(crate) fn write_filtered_diff<Filter>(
diff_filename: &str,
out_dir: &Path,
compare_dir: &Path,
verbose: bool,
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 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();
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
}

View File

@ -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;

View File

@ -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, write_filtered_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<DiffLine>,
}
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<Mismatch> {
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"
@ -2507,43 +2403,17 @@ 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()
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()))
{
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();
}
},
) {
return;
}
match self.config.color {