1
Fork 0

Merge branch 'rust-lang:master' into issue-98861-fix

This commit is contained in:
Dan Vail 2022-08-09 12:52:11 -05:00 committed by GitHub
commit 0436067210
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
162 changed files with 3121 additions and 973 deletions

View file

@ -4626,6 +4626,7 @@ dependencies = [
"rustc_attr", "rustc_attr",
"rustc_data_structures", "rustc_data_structures",
"rustc_errors", "rustc_errors",
"rustc_feature",
"rustc_graphviz", "rustc_graphviz",
"rustc_hir", "rustc_hir",
"rustc_hir_pretty", "rustc_hir_pretty",

View file

@ -417,6 +417,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|| attr.has_name(sym::stable) || attr.has_name(sym::stable)
|| attr.has_name(sym::rustc_const_unstable) || attr.has_name(sym::rustc_const_unstable)
|| attr.has_name(sym::rustc_const_stable) || attr.has_name(sym::rustc_const_stable)
|| attr.has_name(sym::rustc_default_body_unstable)
{ {
struct_span_err!( struct_span_err!(
self.sess, self.sess,

View file

@ -131,6 +131,14 @@ impl ConstStability {
} }
} }
/// Represents the `#[rustc_default_body_unstable]` attribute.
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(HashStable_Generic)]
pub struct DefaultBodyStability {
pub level: StabilityLevel,
pub feature: Symbol,
}
/// The available stability levels. /// The available stability levels.
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
#[derive(HashStable_Generic)] #[derive(HashStable_Generic)]
@ -214,7 +222,8 @@ pub fn find_stability(
sess: &Session, sess: &Session,
attrs: &[Attribute], attrs: &[Attribute],
item_sp: Span, item_sp: Span,
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) { ) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
{
find_stability_generic(sess, attrs.iter(), item_sp) find_stability_generic(sess, attrs.iter(), item_sp)
} }
@ -222,7 +231,7 @@ fn find_stability_generic<'a, I>(
sess: &Session, sess: &Session,
attrs_iter: I, attrs_iter: I,
item_sp: Span, item_sp: Span,
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>) ) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
where where
I: Iterator<Item = &'a Attribute>, I: Iterator<Item = &'a Attribute>,
{ {
@ -230,6 +239,7 @@ where
let mut stab: Option<(Stability, Span)> = None; let mut stab: Option<(Stability, Span)> = None;
let mut const_stab: Option<(ConstStability, Span)> = None; let mut const_stab: Option<(ConstStability, Span)> = None;
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
let mut promotable = false; let mut promotable = false;
let mut allowed_through_unstable_modules = false; let mut allowed_through_unstable_modules = false;
@ -243,6 +253,7 @@ where
sym::stable, sym::stable,
sym::rustc_promotable, sym::rustc_promotable,
sym::rustc_allowed_through_unstable_modules, sym::rustc_allowed_through_unstable_modules,
sym::rustc_default_body_unstable,
] ]
.iter() .iter()
.any(|&s| attr.has_name(s)) .any(|&s| attr.has_name(s))
@ -280,7 +291,7 @@ where
let meta_name = meta.name_or_empty(); let meta_name = meta.name_or_empty();
match meta_name { match meta_name {
sym::rustc_const_unstable | sym::unstable => { sym::rustc_const_unstable | sym::rustc_default_body_unstable | sym::unstable => {
if meta_name == sym::unstable && stab.is_some() { if meta_name == sym::unstable && stab.is_some() {
handle_errors( handle_errors(
&sess.parse_sess, &sess.parse_sess,
@ -295,6 +306,13 @@ where
AttrError::MultipleStabilityLevels, AttrError::MultipleStabilityLevels,
); );
break; break;
} else if meta_name == sym::rustc_default_body_unstable && body_stab.is_some() {
handle_errors(
&sess.parse_sess,
attr.span,
AttrError::MultipleStabilityLevels,
);
break;
} }
let mut feature = None; let mut feature = None;
@ -405,11 +423,16 @@ where
}; };
if sym::unstable == meta_name { if sym::unstable == meta_name {
stab = Some((Stability { level, feature }, attr.span)); stab = Some((Stability { level, feature }, attr.span));
} else { } else if sym::rustc_const_unstable == meta_name {
const_stab = Some(( const_stab = Some((
ConstStability { level, feature, promotable: false }, ConstStability { level, feature, promotable: false },
attr.span, attr.span,
)); ));
} else if sym::rustc_default_body_unstable == meta_name {
body_stab =
Some((DefaultBodyStability { level, feature }, attr.span));
} else {
unreachable!("Unknown stability attribute {meta_name}");
} }
} }
(None, _, _) => { (None, _, _) => {
@ -542,7 +565,7 @@ where
} }
} }
(stab, const_stab) (stab, const_stab, body_stab)
} }
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> { pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {

View file

@ -520,6 +520,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Gives raw access to the `Allocation`, without bounds or alignment checks. /// Gives raw access to the `Allocation`, without bounds or alignment checks.
/// The caller is responsible for calling the access hooks! /// The caller is responsible for calling the access hooks!
///
/// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
fn get_alloc_raw( fn get_alloc_raw(
&self, &self,
id: AllocId, id: AllocId,
@ -589,6 +591,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(&self.get_alloc_raw(id)?.extra) Ok(&self.get_alloc_raw(id)?.extra)
} }
/// Return the `mutability` field of the given allocation.
pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> {
Ok(self.get_alloc_raw(id)?.mutability)
}
/// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks.
/// The caller is responsible for calling the access hooks! /// The caller is responsible for calling the access hooks!
/// ///

View file

@ -772,7 +772,7 @@ impl SyntaxExtension {
) )
}) })
.unwrap_or_else(|| (None, helper_attrs)); .unwrap_or_else(|| (None, helper_attrs));
let (stability, const_stability) = attr::find_stability(&sess, attrs, span); let (stability, const_stability, body_stability) = attr::find_stability(&sess, attrs, span);
if let Some((_, sp)) = const_stability { if let Some((_, sp)) = const_stability {
sess.parse_sess sess.parse_sess
.span_diagnostic .span_diagnostic
@ -784,6 +784,17 @@ impl SyntaxExtension {
) )
.emit(); .emit();
} }
if let Some((_, sp)) = body_stability {
sess.parse_sess
.span_diagnostic
.struct_span_err(sp, "macros cannot have body stability attributes")
.span_label(sp, "invalid body stability attribute")
.span_label(
sess.source_map().guess_head_span(span),
"body stability attribute affects this macro",
)
.emit();
}
SyntaxExtension { SyntaxExtension {
kind, kind,

View file

@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk), ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk),
ungated!(
rustc_default_body_unstable, Normal,
template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk
),
gated!( gated!(
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
"allow_internal_unstable side-steps feature gating and stability checks", "allow_internal_unstable side-steps feature gating and stability checks",

View file

@ -207,6 +207,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
def_ident_span => { table } def_ident_span => { table }
lookup_stability => { table } lookup_stability => { table }
lookup_const_stability => { table } lookup_const_stability => { table }
lookup_default_body_stability => { table }
lookup_deprecation_entry => { table } lookup_deprecation_entry => { table }
visibility => { table } visibility => { table }
unused_generic_params => { table } unused_generic_params => { table }

View file

@ -1029,6 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if should_encode_stability(def_kind) { if should_encode_stability(def_kind) {
self.encode_stability(def_id); self.encode_stability(def_id);
self.encode_const_stability(def_id); self.encode_const_stability(def_id);
self.encode_default_body_stability(def_id);
self.encode_deprecation(def_id); self.encode_deprecation(def_id);
} }
if should_encode_variances(def_kind) { if should_encode_variances(def_kind) {
@ -1385,6 +1386,18 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
} }
fn encode_default_body_stability(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_default_body_stability({:?})", def_id);
// The query lookup can take a measurable amount of time in crates with many items. Check if
// the stability attributes are even enabled before using their queries.
if self.feat.staged_api || self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
if let Some(stab) = self.tcx.lookup_default_body_stability(def_id) {
record!(self.tables.lookup_default_body_stability[def_id] <- stab)
}
}
}
fn encode_deprecation(&mut self, def_id: DefId) { fn encode_deprecation(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_deprecation({:?})", def_id); debug!("EncodeContext::encode_deprecation({:?})", def_id);
if let Some(depr) = self.tcx.lookup_deprecation(def_id) { if let Some(depr) = self.tcx.lookup_deprecation(def_id) {

View file

@ -343,6 +343,7 @@ define_tables! {
def_ident_span: Table<DefIndex, LazyValue<Span>>, def_ident_span: Table<DefIndex, LazyValue<Span>>,
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>, lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>, lookup_const_stability: Table<DefIndex, LazyValue<attr::ConstStability>>,
lookup_default_body_stability: Table<DefIndex, LazyValue<attr::DefaultBodyStability>>,
lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>, lookup_deprecation_entry: Table<DefIndex, LazyValue<attr::Deprecation>>,
// As an optimization, a missing entry indicates an empty `&[]`. // As an optimization, a missing entry indicates an empty `&[]`.
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>, explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,

View file

@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
use crate::ty::{self, DefIdTree, TyCtxt}; use crate::ty::{self, DefIdTree, TyCtxt};
use rustc_ast::NodeId; use rustc_ast::NodeId;
use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diagnostic}; use rustc_errors::{Applicability, Diagnostic};
use rustc_feature::GateIssue; use rustc_feature::GateIssue;
@ -61,6 +61,7 @@ pub struct Index {
/// are filled by the annotator. /// are filled by the annotator.
pub stab_map: FxHashMap<LocalDefId, Stability>, pub stab_map: FxHashMap<LocalDefId, Stability>,
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>, pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>, pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
/// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]`
/// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute
@ -86,6 +87,10 @@ impl Index {
self.const_stab_map.get(&def_id).copied() self.const_stab_map.get(&def_id).copied()
} }
pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option<DefaultBodyStability> {
self.default_body_stab_map.get(&def_id).copied()
}
pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> { pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
self.depr_map.get(&def_id).cloned() self.depr_map.get(&def_id).cloned()
} }
@ -416,6 +421,12 @@ impl<'tcx> TyCtxt<'tcx> {
return EvalResult::Allow; return EvalResult::Allow;
} }
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
let stability = self.lookup_stability(def_id); let stability = self.lookup_stability(def_id);
debug!( debug!(
"stability: \ "stability: \
@ -423,12 +434,6 @@ impl<'tcx> TyCtxt<'tcx> {
def_id, span, stability def_id, span, stability
); );
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
// Issue #38412: private items lack stability markers. // Issue #38412: private items lack stability markers.
if skip_stability_check_due_to_privacy(self, def_id) { if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow; return EvalResult::Allow;
@ -492,6 +497,62 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
/// Evaluates the default-impl stability of an item.
///
/// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
/// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
/// unstable feature otherwise.
pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult {
let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
if !is_staged_api {
return EvalResult::Allow;
}
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
return EvalResult::Allow;
}
let stability = self.lookup_default_body_stability(def_id);
debug!(
"body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
);
// Issue #38412: private items lack stability markers.
if skip_stability_check_due_to_privacy(self, def_id) {
return EvalResult::Allow;
}
match stability {
Some(DefaultBodyStability {
level: attr::Unstable { reason, issue, is_soft, .. },
feature,
}) => {
if span.allows_unstable(feature) {
debug!("body stability: skipping span={:?} since it is internal", span);
return EvalResult::Allow;
}
if self.features().active(feature) {
return EvalResult::Allow;
}
EvalResult::Deny {
feature,
reason: reason.to_opt_reason(),
issue,
suggestion: None,
is_soft,
}
}
Some(_) => {
// Stable APIs are always ok to call
EvalResult::Allow
}
None => EvalResult::Unmarked,
}
}
/// Checks if an item is stable or error out. /// Checks if an item is stable or error out.
/// ///
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not

View file

@ -80,6 +80,8 @@ macro_rules! make_mir_visitor {
self.super_body(body); self.super_body(body);
} }
extra_body_methods!($($mutability)?);
fn visit_basic_block_data( fn visit_basic_block_data(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
@ -287,63 +289,7 @@ macro_rules! make_mir_visitor {
&mut self, &mut self,
body: &$($mutability)? Body<'tcx>, body: &$($mutability)? Body<'tcx>,
) { ) {
let span = body.span; super_body!(self, body, $($mutability, true)?);
if let Some(gen) = &$($mutability)? body.generator {
if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
self.visit_ty(
yield_ty,
TyContext::YieldTy(SourceInfo::outermost(span))
);
}
}
// for best performance, we want to use an iterator rather
// than a for-loop, to avoid calling `body::Body::invalidate` for
// each basic block.
#[allow(unused_macro_rules)]
macro_rules! basic_blocks {
(mut) => (body.basic_blocks_mut().iter_enumerated_mut());
() => (body.basic_blocks().iter_enumerated());
}
for (bb, data) in basic_blocks!($($mutability)?) {
self.visit_basic_block_data(bb, data);
}
for scope in &$($mutability)? body.source_scopes {
self.visit_source_scope_data(scope);
}
self.visit_ty(
$(& $mutability)? body.return_ty(),
TyContext::ReturnTy(SourceInfo::outermost(body.span))
);
for local in body.local_decls.indices() {
self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
}
#[allow(unused_macro_rules)]
macro_rules! type_annotations {
(mut) => (body.user_type_annotations.iter_enumerated_mut());
() => (body.user_type_annotations.iter_enumerated());
}
for (index, annotation) in type_annotations!($($mutability)?) {
self.visit_user_type_annotation(
index, annotation
);
}
for var_debug_info in &$($mutability)? body.var_debug_info {
self.visit_var_debug_info(var_debug_info);
}
self.visit_span($(& $mutability)? body.span);
for const_ in &$($mutability)? body.required_consts {
let location = START_BLOCK.start_location();
self.visit_constant(const_, location);
}
} }
fn super_basic_block_data(&mut self, fn super_basic_block_data(&mut self,
@ -982,12 +928,7 @@ macro_rules! make_mir_visitor {
body: &$($mutability)? Body<'tcx>, body: &$($mutability)? Body<'tcx>,
location: Location location: Location
) { ) {
#[allow(unused_macro_rules)] let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
macro_rules! basic_blocks {
(mut) => (body.basic_blocks_mut());
() => (body.basic_blocks());
}
let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block];
if basic_block.statements.len() == location.statement_index { if basic_block.statements.len() == location.statement_index {
if let Some(ref $($mutability)? terminator) = basic_block.terminator { if let Some(ref $($mutability)? terminator) = basic_block.terminator {
self.visit_terminator(terminator, location) self.visit_terminator(terminator, location)
@ -1002,6 +943,94 @@ macro_rules! make_mir_visitor {
} }
} }
macro_rules! basic_blocks {
($body:ident, mut, true) => {
$body.basic_blocks.as_mut()
};
($body:ident, mut, false) => {
$body.basic_blocks.as_mut_preserves_cfg()
};
($body:ident,) => {
$body.basic_blocks()
};
}
macro_rules! basic_blocks_iter {
($body:ident, mut, $invalidate:tt) => {
basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
};
($body:ident,) => {
basic_blocks!($body,).iter_enumerated()
};
}
macro_rules! extra_body_methods {
(mut) => {
fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
self.super_body_preserves_cfg(body);
}
fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
super_body!(self, body, mut, false);
}
};
() => {};
}
macro_rules! super_body {
($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
let span = $body.span;
if let Some(gen) = &$($mutability)? $body.generator {
if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
$self.visit_ty(
yield_ty,
TyContext::YieldTy(SourceInfo::outermost(span))
);
}
}
for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
$self.visit_basic_block_data(bb, data);
}
for scope in &$($mutability)? $body.source_scopes {
$self.visit_source_scope_data(scope);
}
$self.visit_ty(
$(& $mutability)? $body.return_ty(),
TyContext::ReturnTy(SourceInfo::outermost($body.span))
);
for local in $body.local_decls.indices() {
$self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
}
#[allow(unused_macro_rules)]
macro_rules! type_annotations {
(mut) => ($body.user_type_annotations.iter_enumerated_mut());
() => ($body.user_type_annotations.iter_enumerated());
}
for (index, annotation) in type_annotations!($($mutability)?) {
$self.visit_user_type_annotation(
index, annotation
);
}
for var_debug_info in &$($mutability)? $body.var_debug_info {
$self.visit_var_debug_info(var_debug_info);
}
$self.visit_span($(& $mutability)? $body.span);
for const_ in &$($mutability)? $body.required_consts {
let location = START_BLOCK.start_location();
$self.visit_constant(const_, location);
}
}
}
macro_rules! visit_place_fns { macro_rules! visit_place_fns {
(mut) => { (mut) => {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;

View file

@ -1094,6 +1094,11 @@ rustc_queries! {
separate_provide_extern separate_provide_extern
} }
query lookup_default_body_stability(def_id: DefId) -> Option<attr::DefaultBodyStability> {
desc { |tcx| "looking up default body stability of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
query should_inherit_track_caller(def_id: DefId) -> bool { query should_inherit_track_caller(def_id: DefId) -> bool {
desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) } desc { |tcx| "computing should_inherit_track_caller of `{}`", tcx.def_path_str(def_id) }
} }
@ -1951,6 +1956,14 @@ rustc_queries! {
} }
} }
query is_impossible_method(key: (DefId, DefId)) -> bool {
desc { |tcx|
"checking if {} is impossible to call within {}",
tcx.def_path_str(key.1),
tcx.def_path_str(key.0),
}
}
query method_autoderef_steps( query method_autoderef_steps(
goal: CanonicalTyGoal<'tcx> goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> { ) -> MethodAutoderefStepsResult<'tcx> {

View file

@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! {
rustc_ast::Attribute, rustc_ast::Attribute,
rustc_ast::MacArgs, rustc_ast::MacArgs,
rustc_attr::ConstStability, rustc_attr::ConstStability,
rustc_attr::DefaultBodyStability,
rustc_attr::Deprecation, rustc_attr::Deprecation,
rustc_attr::Stability, rustc_attr::Stability,
rustc_hir::Constness, rustc_hir::Constness,

View file

@ -849,22 +849,22 @@ fn non_exhaustive_match<'p, 'tcx>(
)); ));
} }
[.., prev, last] if prev.span.eq_ctxt(last.span) => { [.., prev, last] if prev.span.eq_ctxt(last.span) => {
if let Ok(snippet) = sm.span_to_snippet(prev.span.between(last.span)) { let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
let comma = if matches!(last.body.kind, hir::ExprKind::Block(..)) && last.span.eq_ctxt(last.body.span)
&& last.span.eq_ctxt(last.body.span) {
{ ""
"" } else {
} else { ","
"," };
}; let spacing = if sm.is_multiline(prev.span.between(last.span)) {
sm.indentation_before(last.span).map(|indent| format!("\n{indent}"))
} else {
Some(" ".to_string())
};
if let Some(spacing) = spacing {
suggestion = Some(( suggestion = Some((
last.span.shrink_to_hi(), last.span.shrink_to_hi(),
format!( format!("{}{}{} => todo!()", comma, spacing, pattern),
"{}{}{} => todo!()",
comma,
snippet.strip_prefix(',').unwrap_or(&snippet),
pattern
),
)); ));
} }
} }

View file

@ -33,7 +33,7 @@ pub struct DeleteNonCodegenStatements<'tcx> {
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements { impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut delete = DeleteNonCodegenStatements { tcx }; let mut delete = DeleteNonCodegenStatements { tcx };
delete.visit_body(body); delete.visit_body_preserves_cfg(body);
body.user_type_annotations.raw.clear(); body.user_type_annotations.raw.clear();
for decl in &mut body.local_decls { for decl in &mut body.local_decls {

View file

@ -951,7 +951,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
} }
fn visit_body(&mut self, body: &mut Body<'tcx>) { fn visit_body(&mut self, body: &mut Body<'tcx>) {
for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
self.visit_basic_block_data(bb, data); self.visit_basic_block_data(bb, data);
} }
} }

View file

@ -90,7 +90,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let patch = MirPatch::new(body); let patch = MirPatch::new(body);
let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() }; let mut checker = DerefChecker { tcx, patcher: patch, local_decls: body.local_decls.clone() };
for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() { for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
checker.visit_basic_block_data(bb, data); checker.visit_basic_block_data(bb, data);
} }

View file

@ -116,7 +116,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch }; ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
for (block, BasicBlockData { statements, terminator, .. }) in for (block, BasicBlockData { statements, terminator, .. }) in
body.basic_blocks.as_mut().iter_enumerated_mut() body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut()
{ {
let mut index = 0; let mut index = 0;
for statement in statements { for statement in statements {

View file

@ -53,10 +53,10 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
def_id, returned_local def_id, returned_local
); );
RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body); RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body);
// Clean up the `NOP`s we inserted for statements made useless by our renaming. // Clean up the `NOP`s we inserted for statements made useless by our renaming.
for block_data in body.basic_blocks_mut() { for block_data in body.basic_blocks.as_mut_preserves_cfg() {
block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop); block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop);
} }

View file

@ -19,7 +19,7 @@ impl<'tcx> MirPass<'tcx> for RevealAll {
} }
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
RevealAllVisitor { tcx, param_env }.visit_body(body); RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
} }
} }

View file

@ -412,7 +412,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
if map.iter().any(Option::is_none) { if map.iter().any(Option::is_none) {
// Update references to all vars and tmps now // Update references to all vars and tmps now
let mut updater = LocalUpdater { map, tcx }; let mut updater = LocalUpdater { map, tcx };
updater.visit_body(body); updater.visit_body_preserves_cfg(body);
body.local_decls.shrink_to_fit(); body.local_decls.shrink_to_fit();
} }
@ -548,7 +548,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
while modified { while modified {
modified = false; modified = false;
for data in body.basic_blocks_mut() { for data in body.basic_blocks.as_mut_preserves_cfg() {
// Remove unnecessary StorageLive and StorageDead annotations. // Remove unnecessary StorageLive and StorageDead annotations.
data.statements.retain(|statement| { data.statements.retain(|statement| {
let keep = match &statement.kind { let keep = match &statement.kind {

View file

@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> {
} }
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> { fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
let stab_attrs = let stab_attrs = [
[sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable]; sym::stable,
sym::unstable,
sym::rustc_const_stable,
sym::rustc_const_unstable,
sym::rustc_default_body_unstable,
];
// Find a stability attribute: one of #[stable(…)], #[unstable(…)], // Find a stability attribute: one of #[stable(…)], #[unstable(…)],
// #[rustc_const_stable(…)], or #[rustc_const_unstable(…)]. // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
let meta_kind = attr.meta_kind(); let meta_kind = attr.meta_kind();
if let Some(MetaItemKind::List(ref metas)) = meta_kind { if let Some(MetaItemKind::List(ref metas)) = meta_kind {
@ -53,8 +58,12 @@ impl<'tcx> LibFeatureCollector<'tcx> {
// This additional check for stability is to make sure we // This additional check for stability is to make sure we
// don't emit additional, irrelevant errors for malformed // don't emit additional, irrelevant errors for malformed
// attributes. // attributes.
let is_unstable = let is_unstable = matches!(
matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable); *stab_attr,
sym::unstable
| sym::rustc_const_unstable
| sym::rustc_default_body_unstable
);
if since.is_some() || is_unstable { if since.is_some() || is_unstable {
return Some((feature, since, attr.span)); return Some((feature, since, attr.span));
} }

View file

@ -1,11 +1,12 @@
//! Checks validity of naked functions. //! Checks validity of naked functions.
use rustc_ast::{Attribute, InlineAsmOptions}; use rustc_ast::InlineAsmOptions;
use rustc_errors::{struct_span_err, Applicability}; use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind}; use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
@ -13,71 +14,58 @@ use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
}
pub(crate) fn provide(providers: &mut Providers) { pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_naked_functions, ..*providers }; *providers = Providers { check_mod_naked_functions, ..*providers };
} }
struct CheckNakedFunctions<'tcx> { fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx: TyCtxt<'tcx>, let items = tcx.hir_module_items(module_def_id);
} for def_id in items.definitions() {
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> { continue;
fn visit_fn(
&mut self,
fk: FnKind<'_>,
_fd: &'tcx hir::FnDecl<'tcx>,
body_id: hir::BodyId,
span: Span,
hir_id: HirId,
) {
let ident_span;
let fn_header;
match fk {
FnKind::Closure => {
// Closures with a naked attribute are rejected during attribute
// check. Don't validate them any further.
return;
}
FnKind::ItemFn(ident, _, ref header, ..) => {
ident_span = ident.span;
fn_header = header;
}
FnKind::Method(ident, ref sig, ..) => {
ident_span = ident.span;
fn_header = &sig.header;
}
} }
let attrs = self.tcx.hir().attrs(hir_id); let naked = tcx.has_attr(def_id.to_def_id(), sym::naked);
let naked = attrs.iter().any(|attr| attr.has_name(sym::naked)); if !naked {
if naked { continue;
let body = self.tcx.hir().body(body_id);
check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
check_no_patterns(self.tcx, body.params);
check_no_parameters_use(self.tcx, body);
check_asm(self.tcx, body, span);
check_inline(self.tcx, attrs);
} }
let (fn_header, body_id) = match tcx.hir().get_by_def_id(def_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })
| hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),
..
})
| hir::Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(sig, body_id),
..
}) => (sig.header, *body_id),
_ => continue,
};
let body = tcx.hir().body(body_id);
check_abi(tcx, def_id, fn_header.abi);
check_no_patterns(tcx, body.params);
check_no_parameters_use(tcx, body);
check_asm(tcx, def_id, body);
check_inline(tcx, def_id);
} }
} }
/// Check that the function isn't inlined. /// Check that the function isn't inlined.
fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) { fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) { let attrs = tcx.get_attrs(def_id.to_def_id(), sym::inline);
for attr in attrs {
tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit(); tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
} }
} }
/// Checks that function uses non-Rust ABI. /// Checks that function uses non-Rust ABI.
fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) { fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust { if abi == Abi::Rust {
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, fn_ident_span, |lint| { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id);
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
lint.build("Rust ABI is unsupported in naked functions").emit(); lint.build("Rust ABI is unsupported in naked functions").emit();
}); });
} }
@ -141,7 +129,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
} }
/// Checks that function body contains a single inline assembly block. /// Checks that function body contains a single inline assembly block.
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) { fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
let mut this = CheckInlineAssembly { tcx, items: Vec::new() }; let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
this.visit_body(body); this.visit_body(body);
if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] { if let [(ItemKind::Asm | ItemKind::Err, _)] = this.items[..] {
@ -149,7 +137,7 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span
} else { } else {
let mut diag = struct_span_err!( let mut diag = struct_span_err!(
tcx.sess, tcx.sess,
fn_span, tcx.def_span(def_id),
E0787, E0787,
"naked functions must contain a single asm block" "naked functions must contain a single asm block"
); );

View file

@ -1,8 +1,9 @@
//! A pass that annotates every item and method with its stability level, //! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes. //! propagating default levels lexically from parent to children ast nodes.
use attr::StabilityLevel; use rustc_attr::{
use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason}; self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{struct_span_err, Applicability}; use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir; use rustc_hir as hir;
@ -161,7 +162,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
return; return;
} }
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp); let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let mut const_span = None; let mut const_span = None;
let const_stab = const_stab.map(|(const_stab, const_span_node)| { let const_stab = const_stab.map(|(const_stab, const_span_node)| {
@ -209,6 +210,13 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
} }
} }
if let Some((body_stab, _span)) = body_stab {
// FIXME: check that this item can have body stability
self.index.default_body_stab_map.insert(def_id, body_stab);
debug!(?self.index.default_body_stab_map);
}
let stab = stab.map(|(stab, span)| { let stab = stab.map(|(stab, span)| {
// Error if prohibited, or can't inherit anything from a container. // Error if prohibited, or can't inherit anything from a container.
if kind == AnnotationKind::Prohibited if kind == AnnotationKind::Prohibited
@ -613,6 +621,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
let mut index = Index { let mut index = Index {
stab_map: Default::default(), stab_map: Default::default(),
const_stab_map: Default::default(), const_stab_map: Default::default(),
default_body_stab_map: Default::default(),
depr_map: Default::default(), depr_map: Default::default(),
implications: Default::default(), implications: Default::default(),
}; };
@ -673,6 +682,9 @@ pub(crate) fn provide(providers: &mut Providers) {
stability_implications: |tcx, _| tcx.stability().implications.clone(), stability_implications: |tcx, _| tcx.stability().implications.clone(),
lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()), lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
lookup_default_body_stability: |tcx, id| {
tcx.stability().local_default_body_stability(id.expect_local())
},
lookup_deprecation_entry: |tcx, id| { lookup_deprecation_entry: |tcx, id| {
tcx.stability().local_deprecation_entry(id.expect_local()) tcx.stability().local_deprecation_entry(id.expect_local())
}, },
@ -723,7 +735,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
let features = self.tcx.features(); let features = self.tcx.features();
if features.staged_api { if features.staged_api {
let attrs = self.tcx.hir().attrs(item.hir_id()); let attrs = self.tcx.hir().attrs(item.hir_id());
let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item.span); let (stab, const_stab, _) =
attr::find_stability(&self.tcx.sess, attrs, item.span);
// If this impl block has an #[unstable] attribute, give an // If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because // error if all involved types and traits are stable, because

View file

@ -2544,12 +2544,15 @@ fn show_candidates(
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
if let [first, .., last] = &path[..] { if let [first, .., last] = &path[..] {
err.span_suggestion_verbose( let sp = first.ident.span.until(last.ident.span);
first.ident.span.until(last.ident.span), if sp.can_be_used_for_suggestions() {
&format!("if you import `{}`, refer to it directly", last.ident), err.span_suggestion_verbose(
"", sp,
Applicability::Unspecified, &format!("if you import `{}`, refer to it directly", last.ident),
); "",
Applicability::Unspecified,
);
}
} }
} else { } else {
msg.push(':'); msg.push(':');

View file

@ -1218,6 +1218,7 @@ symbols! {
rustc_conversion_suggestion, rustc_conversion_suggestion,
rustc_deallocator, rustc_deallocator,
rustc_def_path, rustc_def_path,
rustc_default_body_unstable,
rustc_diagnostic_item, rustc_diagnostic_item,
rustc_diagnostic_macros, rustc_diagnostic_macros,
rustc_dirty, rustc_dirty,

View file

@ -1315,6 +1315,13 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
error: &MismatchedProjectionTypes<'tcx>, error: &MismatchedProjectionTypes<'tcx>,
); );
fn maybe_detailed_projection_msg(
&self,
pred: ty::ProjectionPredicate<'tcx>,
normalized_ty: ty::Term<'tcx>,
expected_ty: ty::Term<'tcx>,
) -> Option<String>;
fn fuzzy_match_tys( fn fuzzy_match_tys(
&self, &self,
a: Ty<'tcx>, a: Ty<'tcx>,
@ -1542,23 +1549,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
normalized_ty, normalized_ty,
data.term, data.term,
) { ) {
values = Some(infer::ValuePairs::Terms(ExpectedFound::new( values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
is_normalized_ty_expected,
normalized_ty,
data.term,
)));
err_buf = error; err_buf = error;
err = &err_buf; err = &err_buf;
} }
} }
let mut diag = struct_span_err!( let msg = values
self.tcx.sess, .and_then(|(predicate, _, normalized_ty, expected_ty)| {
obligation.cause.span, self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
E0271, })
"type mismatch resolving `{}`", .unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
predicate let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
);
let secondary_span = match predicate.kind().skip_binder() { let secondary_span = match predicate.kind().skip_binder() {
ty::PredicateKind::Projection(proj) => self ty::PredicateKind::Projection(proj) => self
.tcx .tcx
@ -1596,7 +1599,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
&mut diag, &mut diag,
&obligation.cause, &obligation.cause,
secondary_span, secondary_span,
values, values.map(|(_, is_normalized_ty_expected, normalized_ty, term)| {
infer::ValuePairs::Terms(ExpectedFound::new(
is_normalized_ty_expected,
normalized_ty,
term,
))
}),
err, err,
true, true,
false, false,
@ -1606,6 +1615,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
}); });
} }
fn maybe_detailed_projection_msg(
&self,
pred: ty::ProjectionPredicate<'tcx>,
normalized_ty: ty::Term<'tcx>,
expected_ty: ty::Term<'tcx>,
) -> Option<String> {
let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
let self_ty = pred.projection_ty.self_ty();
if Some(pred.projection_ty.item_def_id) == self.tcx.lang_items().fn_once_output() {
Some(format!(
"expected `{self_ty}` to be a {fn_kind} that returns `{expected_ty}`, but it returns `{normalized_ty}`",
fn_kind = self_ty.prefix_string(self.tcx)
))
} else if Some(trait_def_id) == self.tcx.lang_items().future_trait() {
Some(format!(
"expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it resolves to `{normalized_ty}`"
))
} else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
Some(format!(
"expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it yields `{normalized_ty}`"
))
} else {
None
}
}
fn fuzzy_match_tys( fn fuzzy_match_tys(
&self, &self,
mut a: Ty<'tcx>, mut a: Ty<'tcx>,

View file

@ -34,7 +34,10 @@ use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; use rustc_middle::ty::{
self, DefIdTree, GenericParamDefKind, Subst, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
VtblEntry,
};
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -503,6 +506,77 @@ fn subst_and_check_impossible_predicates<'tcx>(
result result
} }
/// Checks whether a trait's method is impossible to call on a given impl.
///
/// This only considers predicates that reference the impl's generics, and not
/// those that reference the method's generics.
fn is_impossible_method<'tcx>(
tcx: TyCtxt<'tcx>,
(impl_def_id, trait_item_def_id): (DefId, DefId),
) -> bool {
struct ReferencesOnlyParentGenerics<'tcx> {
tcx: TyCtxt<'tcx>,
generics: &'tcx ty::Generics,
trait_item_def_id: DefId,
}
impl<'tcx> ty::TypeVisitor<'tcx> for ReferencesOnlyParentGenerics<'tcx> {
type BreakTy = ();
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// If this is a parameter from the trait item's own generics, then bail
if let ty::Param(param) = t.kind()
&& let param_def_id = self.generics.type_param(param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
t.super_visit_with(self)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ReEarlyBound(param) = r.kind()
&& let param_def_id = self.generics.region_param(&param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
r.super_visit_with(self)
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ConstKind::Param(param) = ct.kind()
&& let param_def_id = self.generics.const_param(&param, self.tcx).def_id
&& self.tcx.parent(param_def_id) == self.trait_item_def_id
{
return ControlFlow::BREAK;
}
ct.super_visit_with(self)
}
}
let generics = tcx.generics_of(trait_item_def_id);
let predicates = tcx.predicates_of(trait_item_def_id);
let impl_trait_ref =
tcx.impl_trait_ref(impl_def_id).expect("expected impl to correspond to trait");
let param_env = tcx.param_env(impl_def_id);
let mut visitor = ReferencesOnlyParentGenerics { tcx, generics, trait_item_def_id };
let predicates_for_trait = predicates.predicates.iter().filter_map(|(pred, span)| {
if pred.visit_with(&mut visitor).is_continue() {
Some(Obligation::new(
ObligationCause::dummy_with_span(*span),
param_env,
ty::EarlyBinder(*pred).subst(tcx, impl_trait_ref.substs),
))
} else {
None
}
});
tcx.infer_ctxt().ignoring_regions().enter(|ref infcx| {
let mut fulfill_ctxt = <dyn TraitEngine<'_>>::new(tcx);
fulfill_ctxt.register_predicate_obligations(infcx, predicates_for_trait);
!fulfill_ctxt.select_all_or_error(infcx).is_empty()
})
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum VtblSegment<'tcx> { enum VtblSegment<'tcx> {
MetadataDSA, MetadataDSA,
@ -883,6 +957,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
vtable_entries, vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot, vtable_trait_upcasting_coercion_new_vptr_slot,
subst_and_check_impossible_predicates, subst_and_check_impossible_predicates,
is_impossible_method,
try_unify_abstract_consts: |tcx, param_env_and| { try_unify_abstract_consts: |tcx, param_env_and| {
let (param_env, (a, b)) = param_env_and.into_parts(); let (param_env, (a, b)) = param_env_and.into_parts();
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env) const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)

View file

@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
rustc_lint = { path = "../rustc_lint" } rustc_lint = { path = "../rustc_lint" }
rustc_serialize = { path = "../rustc_serialize" } rustc_serialize = { path = "../rustc_serialize" }
rustc_type_ir = { path = "../rustc_type_ir" } rustc_type_ir = { path = "../rustc_type_ir" }
rustc_feature = { path = "../rustc_feature" }

View file

@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::Obligation; use rustc_infer::traits::Obligation;
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::util::{Discr, IntTypeExt};
@ -32,7 +33,6 @@ use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt}; use rustc_trait_selection::traits::{self, ObligationCtxt};
use rustc_ty_utils::representability::{self, Representability}; use rustc_ty_utils::representability::{self, Representability};
use std::iter;
use std::ops::ControlFlow; use std::ops::ControlFlow;
pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
@ -1104,12 +1104,28 @@ fn check_impl_items_against_trait<'tcx>(
missing_items.push(tcx.associated_item(trait_item_id)); missing_items.push(tcx.associated_item(trait_item_id));
} }
if let Some(required_items) = &must_implement_one_of { // true if this item is specifically implemented in this impl
// true if this item is specifically implemented in this impl let is_implemented_here = ancestors
let is_implemented_here = ancestors .leaf_def(tcx, trait_item_id)
.leaf_def(tcx, trait_item_id) .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
if !is_implemented_here {
match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {
EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(
tcx,
full_impl_span,
trait_item_id,
feature,
reason,
issue,
),
// Unmarked default bodies are considered stable (at least for now).
EvalResult::Allow | EvalResult::Unmarked => {}
}
}
if let Some(required_items) = &must_implement_one_of {
if is_implemented_here { if is_implemented_here {
let trait_item = tcx.associated_item(trait_item_id); let trait_item = tcx.associated_item(trait_item_id);
if required_items.contains(&trait_item.ident(tcx)) { if required_items.contains(&trait_item.ident(tcx)) {
@ -1494,76 +1510,109 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
} }
} }
let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len()); detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
// This tracks the previous variant span (in the loop) incase we need it for diagnostics
let mut prev_variant_span: Span = DUMMY_SP;
for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) {
// Check for duplicate discriminant values
if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) {
let variant_did = def.variant(VariantIdx::new(i)).def_id;
let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local());
let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
let i_span = match variant_i.disr_expr {
Some(ref expr) => tcx.hir().span(expr.hir_id),
None => tcx.def_span(variant_did),
};
let span = match v.disr_expr {
Some(ref expr) => tcx.hir().span(expr.hir_id),
None => v.span,
};
let display_discr = format_discriminant_overflow(tcx, v, discr);
let display_discr_i = format_discriminant_overflow(tcx, variant_i, disr_vals[i]);
let no_disr = v.disr_expr.is_none();
let mut err = struct_span_err!(
tcx.sess,
sp,
E0081,
"discriminant value `{}` assigned more than once",
discr,
);
err.span_label(i_span, format!("first assignment of {display_discr_i}"));
err.span_label(span, format!("second assignment of {display_discr}"));
if no_disr {
err.span_label(
prev_variant_span,
format!(
"assigned discriminant for `{}` was incremented from this discriminant",
v.ident
),
);
}
err.emit();
}
disr_vals.push(discr);
prev_variant_span = v.span;
}
check_representable(tcx, sp, def_id); check_representable(tcx, sp, def_id);
check_transparent(tcx, sp, def); check_transparent(tcx, sp, def);
} }
/// In the case that a discriminant is both a duplicate and an overflowing literal, /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
/// we insert both the assigned discriminant and the literal it overflowed from into the formatted fn detect_discriminant_duplicate<'tcx>(
/// output. Otherwise we format the discriminant normally.
fn format_discriminant_overflow<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
variant: &hir::Variant<'_>, mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
dis: Discr<'tcx>, vs: &'tcx [hir::Variant<'tcx>],
) -> String { self_span: Span,
if let Some(expr) = &variant.disr_expr { ) {
let body = &tcx.hir().body(expr.body).value; // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
if let hir::ExprKind::Lit(lit) = &body.kind // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node let report = |dis: Discr<'tcx>,
&& dis.val != *lit_value idx: usize,
{ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| {
return format!("`{dis}` (overflowed from `{lit_value}`)"); let var = &vs[idx]; // HIR for the duplicate discriminant
} let (span, display_discr) = match var.disr_expr {
} Some(ref expr) => {
// In the case the discriminant is both a duplicate and overflowed, let the user know
if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& *lit_value != dis.val
{
(tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
// Otherwise, format the value as-is
} else {
(tcx.hir().span(expr.hir_id), format!("`{dis}`"))
}
}
None => {
// At this point we know this discriminant is a duplicate, and was not explicitly
// assigned by the user. Here we iterate backwards to fetch the HIR for the last
// explictly assigned discriminant, and letting the user know that this was the
// increment startpoint, and how many steps from there leading to the duplicate
if let Some((n, hir::Variant { span, ident, .. })) =
vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
{
let ve_ident = var.ident;
let n = n + 1;
let sp = if n > 1 { "variants" } else { "variant" };
format!("`{dis}`") err.span_label(
*span,
format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
);
}
(vs[idx].span, format!("`{dis}`"))
}
};
err.span_label(span, format!("{display_discr} assigned here"));
};
// Here we loop through the discriminants, comparing each discriminant to another.
// When a duplicate is detected, we instatiate an error and point to both
// initial and duplicate value. The duplicate discriminant is then discarded by swapping
// it with the last element and decrementing the `vec.len` (which is why we have to evaluate
// `discrs.len()` anew every iteration, and why this could be tricky to do in a functional
// style as we are mutating `discrs` on the fly).
let mut i = 0;
while i < discrs.len() {
let hir_var_i_idx = discrs[i].0.index();
let mut error: Option<DiagnosticBuilder<'_, _>> = None;
let mut o = i + 1;
while o < discrs.len() {
let hir_var_o_idx = discrs[o].0.index();
if discrs[i].1.val == discrs[o].1.val {
let err = error.get_or_insert_with(|| {
let mut ret = struct_span_err!(
tcx.sess,
self_span,
E0081,
"discriminant value `{}` assigned more than once",
discrs[i].1,
);
report(discrs[i].1, hir_var_i_idx, &mut ret);
ret
});
report(discrs[o].1, hir_var_o_idx, err);
// Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
discrs[o] = *discrs.last().unwrap();
discrs.pop();
} else {
o += 1;
}
}
if let Some(mut e) = error {
e.emit();
}
i += 1;
}
} }
pub(super) fn check_type_params_are_used<'tcx>( pub(super) fn check_type_params_are_used<'tcx>(

View file

@ -1589,11 +1589,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
) { ) {
let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;}; let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
let mut span: MultiSpan = vec![loop_span].into(); let mut span: MultiSpan = vec![loop_span].into();
span.push_span_label(loop_span, "this might have zero elements to iterate on".to_string()); span.push_span_label(loop_span, "this might have zero elements to iterate on");
for ret_expr in ret_exprs { for ret_expr in ret_exprs {
span.push_span_label( span.push_span_label(
ret_expr.span, ret_expr.span,
"if the loop doesn't execute, this value would never get returned".to_string(), "if the loop doesn't execute, this value would never get returned",
); );
} }
err.span_note( err.span_note(

View file

@ -50,7 +50,6 @@ use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned}; use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Pos};
use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_target::spec::abi::Abi::RustIntrinsic;
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCauseCode}; use rustc_trait_selection::traits::{self, ObligationCauseCode};
@ -2398,37 +2397,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr, expr,
Some(span), Some(span),
); );
} else if let ty::RawPtr(ty_and_mut) = expr_t.kind()
&& let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
&& let ExprKind::Field(base_expr, _) = expr.kind
&& adt_def.variants().len() == 1
&& adt_def
.variants()
.iter()
.next()
.unwrap()
.fields
.iter()
.any(|f| f.ident(self.tcx) == field)
{
err.multipart_suggestion(
"to access the field, dereference first",
vec![
(base_expr.span.shrink_to_lo(), "(*".to_string()),
(base_expr.span.shrink_to_hi(), ")".to_string()),
],
Applicability::MaybeIncorrect,
);
} else { } else {
let mut found = false; err.help("methods are immutable and cannot be assigned to");
if let ty::RawPtr(ty_and_mut) = expr_t.kind()
&& let ty::Adt(adt_def, _) = ty_and_mut.ty.kind()
{
if adt_def.variants().len() == 1
&& adt_def
.variants()
.iter()
.next()
.unwrap()
.fields
.iter()
.any(|f| f.ident(self.tcx) == field)
{
if let Some(dot_loc) = expr_snippet.rfind('.') {
found = true;
err.span_suggestion(
expr.span.with_hi(expr.span.lo() + BytePos::from_usize(dot_loc)),
"to access the field, dereference first",
format!("(*{})", &expr_snippet[0..dot_loc]),
Applicability::MaybeIncorrect,
);
}
}
}
if !found {
err.help("methods are immutable and cannot be assigned to");
}
} }
err.emit(); err.emit();

View file

@ -112,7 +112,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirIdMap, ImplicitSelfKind, Node}; use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
@ -122,13 +121,14 @@ use rustc_session::parse::feature_err;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::source_map::DUMMY_SP; use rustc_span::source_map::DUMMY_SP;
use rustc_span::symbol::{kw, Ident}; use rustc_span::symbol::{kw, Ident};
use rustc_span::{self, BytePos, Span}; use rustc_span::{self, BytePos, Span, Symbol};
use rustc_target::abi::VariantIdx; use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use std::cell::RefCell; use std::cell::RefCell;
use std::num::NonZeroU32;
use crate::require_c_abi_if_c_variadic; use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter; use crate::util::common::indenter;
@ -662,6 +662,37 @@ fn missing_items_must_implement_one_of_err(
err.emit(); err.emit();
} }
fn default_body_is_unstable(
tcx: TyCtxt<'_>,
impl_span: Span,
item_did: DefId,
feature: Symbol,
reason: Option<Symbol>,
issue: Option<NonZeroU32>,
) {
let missing_item_name = &tcx.associated_item(item_did).name;
let use_of_unstable_library_feature_note = match reason {
Some(r) => format!("use of unstable library feature '{feature}': {r}"),
None => format!("use of unstable library feature '{feature}'"),
};
let mut err = struct_span_err!(
tcx.sess,
impl_span,
E0046,
"not all trait items implemented, missing: `{missing_item_name}`",
);
err.note(format!("default implementation of `{missing_item_name}` is unstable"));
err.note(use_of_unstable_library_feature_note);
rustc_session::parse::add_feature_diagnostics_for_issue(
&mut err,
&tcx.sess.parse_sess,
feature,
rustc_feature::GateIssue::Library(issue),
);
err.emit();
}
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
fn bounds_from_generic_predicates<'tcx>( fn bounds_from_generic_predicates<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,

View file

@ -318,19 +318,11 @@ impl Duration {
/// assert_eq!(duration.as_secs(), 5); /// assert_eq!(duration.as_secs(), 5);
/// ``` /// ```
/// ///
/// To determine the total number of seconds represented by the `Duration`, /// To determine the total number of seconds represented by the `Duration`
/// use `as_secs` in combination with [`subsec_nanos`]: /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`]
///
/// ```
/// use std::time::Duration;
///
/// let duration = Duration::new(5, 730023852);
///
/// assert_eq!(5.730023852,
/// duration.as_secs() as f64
/// + duration.subsec_nanos() as f64 * 1e-9);
/// ```
/// ///
/// [`as_secs_f32`]: Duration::as_secs_f64
/// [`as_secs_f64`]: Duration::as_secs_f32
/// [`subsec_nanos`]: Duration::subsec_nanos /// [`subsec_nanos`]: Duration::subsec_nanos
#[stable(feature = "duration", since = "1.3.0")] #[stable(feature = "duration", since = "1.3.0")]
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]

View file

@ -628,6 +628,10 @@ impl Step for Miri {
cargo.env("MIRI_HOST_SYSROOT", sysroot); cargo.env("MIRI_HOST_SYSROOT", sysroot);
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
cargo.env("MIRI", miri); cargo.env("MIRI", miri);
// propagate --bless
if builder.config.cmd.bless() {
cargo.env("MIRI_BLESS", "Gesundheit");
}
cargo.arg("--").args(builder.config.cmd.test_args()); cargo.arg("--").args(builder.config.cmd.test_args());

View file

@ -88,8 +88,8 @@ def check_type(ty):
for bound in binding["binding"]["constraint"]: for bound in binding["binding"]["constraint"]:
check_generic_bound(bound) check_generic_bound(bound)
elif "parenthesized" in args: elif "parenthesized" in args:
for ty in args["parenthesized"]["inputs"]: for input_ty in args["parenthesized"]["inputs"]:
check_type(ty) check_type(input_ty)
if args["parenthesized"]["output"]: if args["parenthesized"]["output"]:
check_type(args["parenthesized"]["output"]) check_type(args["parenthesized"]["output"])
if not valid_id(ty["inner"]["id"]): if not valid_id(ty["inner"]["id"]):

View file

@ -348,15 +348,13 @@ where
fn make_final_bounds( fn make_final_bounds(
&self, &self,
ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>, ty_to_bounds: FxHashMap<Type, FxHashSet<GenericBound>>,
ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)>, ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)>,
lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>, lifetime_to_bounds: FxHashMap<Lifetime, FxHashSet<GenericBound>>,
) -> Vec<WherePredicate> { ) -> Vec<WherePredicate> {
ty_to_bounds ty_to_bounds
.into_iter() .into_iter()
.flat_map(|(ty, mut bounds)| { .flat_map(|(ty, mut bounds)| {
if let Some(data) = ty_to_fn.get(&ty) { if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) {
let (poly_trait, output) =
(data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
let mut new_path = poly_trait.trait_.clone(); let mut new_path = poly_trait.trait_.clone();
let last_segment = new_path.segments.pop().expect("segments were empty"); let last_segment = new_path.segments.pop().expect("segments were empty");
@ -374,8 +372,9 @@ where
GenericArgs::Parenthesized { inputs, output } => (inputs, output), GenericArgs::Parenthesized { inputs, output } => (inputs, output),
}; };
let output = output.as_ref().cloned().map(Box::new);
if old_output.is_some() && old_output != output { if old_output.is_some() && old_output != output {
panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, data.1); panic!("Output mismatch for {:?} {:?} {:?}", ty, old_output, output);
} }
let new_params = GenericArgs::Parenthesized { inputs: old_input, output }; let new_params = GenericArgs::Parenthesized { inputs: old_input, output };
@ -385,7 +384,10 @@ where
.push(PathSegment { name: last_segment.name, args: new_params }); .push(PathSegment { name: last_segment.name, args: new_params });
bounds.insert(GenericBound::TraitBound( bounds.insert(GenericBound::TraitBound(
PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params }, PolyTrait {
trait_: new_path,
generic_params: poly_trait.generic_params.clone(),
},
hir::TraitBoundModifier::None, hir::TraitBoundModifier::None,
)); ));
} }
@ -471,10 +473,10 @@ where
let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default(); let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = Default::default();
let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default(); let mut ty_to_traits: FxHashMap<Type, FxHashSet<Path>> = Default::default();
let mut ty_to_fn: FxHashMap<Type, (Option<PolyTrait>, Option<Type>)> = Default::default(); let mut ty_to_fn: FxHashMap<Type, (PolyTrait, Option<Type>)> = Default::default();
for p in clean_where_predicates { for p in clean_where_predicates {
let (orig_p, p) = (p, p.clean(self.cx)); let (orig_p, p) = (p, clean_predicate(p, self.cx));
if p.is_none() { if p.is_none() {
continue; continue;
} }
@ -535,8 +537,8 @@ where
if is_fn { if is_fn {
ty_to_fn ty_to_fn
.entry(ty.clone()) .entry(ty.clone())
.and_modify(|e| *e = (Some(poly_trait.clone()), e.1.clone())) .and_modify(|e| *e = (poly_trait.clone(), e.1.clone()))
.or_insert(((Some(poly_trait.clone())), None)); .or_insert(((poly_trait.clone()), None));
ty_to_bounds.entry(ty.clone()).or_default(); ty_to_bounds.entry(ty.clone()).or_default();
} else { } else {
@ -559,7 +561,13 @@ where
.and_modify(|e| { .and_modify(|e| {
*e = (e.0.clone(), Some(rhs.ty().unwrap().clone())) *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
}) })
.or_insert((None, Some(rhs.ty().unwrap().clone()))); .or_insert((
PolyTrait {
trait_: trait_.clone(),
generic_params: Vec::new(),
},
Some(rhs.ty().unwrap().clone()),
));
continue; continue;
} }

View file

@ -145,6 +145,7 @@ pub(crate) fn try_inline_glob(
cx: &mut DocContext<'_>, cx: &mut DocContext<'_>,
res: Res, res: Res,
visited: &mut FxHashSet<DefId>, visited: &mut FxHashSet<DefId>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Option<Vec<clean::Item>> { ) -> Option<Vec<clean::Item>> {
let did = res.opt_def_id()?; let did = res.opt_def_id()?;
if did.is_local() { if did.is_local() {
@ -153,8 +154,17 @@ pub(crate) fn try_inline_glob(
match res { match res {
Res::Def(DefKind::Mod, did) => { Res::Def(DefKind::Mod, did) => {
let m = build_module(cx, did, visited); let mut items = build_module_items(cx, did, visited, inlined_names);
Some(m.items) items.drain_filter(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
// it takes priority over the inlined stuff.
!inlined_names.insert((item.type_(), name))
} else {
false
}
});
Some(items)
} }
// glob imports on things like enums aren't inlined even for local exports, so just bail // glob imports on things like enums aren't inlined even for local exports, so just bail
_ => None, _ => None,
@ -517,6 +527,18 @@ fn build_module(
did: DefId, did: DefId,
visited: &mut FxHashSet<DefId>, visited: &mut FxHashSet<DefId>,
) -> clean::Module { ) -> clean::Module {
let items = build_module_items(cx, did, visited, &mut FxHashSet::default());
let span = clean::Span::new(cx.tcx.def_span(did));
clean::Module { items, span }
}
fn build_module_items(
cx: &mut DocContext<'_>,
did: DefId,
visited: &mut FxHashSet<DefId>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<clean::Item> {
let mut items = Vec::new(); let mut items = Vec::new();
// If we're re-exporting a re-export it may actually re-export something in // If we're re-exporting a re-export it may actually re-export something in
@ -526,7 +548,13 @@ fn build_module(
if item.vis.is_public() { if item.vis.is_public() {
let res = item.res.expect_non_local(); let res = item.res.expect_non_local();
if let Some(def_id) = res.mod_def_id() { if let Some(def_id) = res.mod_def_id() {
if did == def_id || !visited.insert(def_id) { // If we're inlining a glob import, it's possible to have
// two distinct modules with the same name. We don't want to
// inline it, or mark any of its contents as visited.
if did == def_id
|| inlined_names.contains(&(ItemType::Module, item.ident.name))
|| !visited.insert(def_id)
{
continue; continue;
} }
} }
@ -563,8 +591,7 @@ fn build_module(
} }
} }
let span = clean::Span::new(cx.tcx.def_span(did)); items
clean::Module { items, span }
} }
pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {

View file

@ -71,7 +71,7 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
// priority to the not-imported one, so we should, too. // priority to the not-imported one, so we should, too.
items.extend(self.items.iter().flat_map(|(item, renamed)| { items.extend(self.items.iter().flat_map(|(item, renamed)| {
// First, lower everything other than imports. // First, lower everything other than imports.
if matches!(item.kind, hir::ItemKind::Use(..)) { if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
return Vec::new(); return Vec::new();
} }
let v = clean_maybe_renamed_item(cx, item, *renamed); let v = clean_maybe_renamed_item(cx, item, *renamed);
@ -84,20 +84,13 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
})); }));
items.extend(self.items.iter().flat_map(|(item, renamed)| { items.extend(self.items.iter().flat_map(|(item, renamed)| {
// Now we actually lower the imports, skipping everything else. // Now we actually lower the imports, skipping everything else.
if !matches!(item.kind, hir::ItemKind::Use(..)) { if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
return Vec::new(); let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
} else {
// skip everything else
Vec::new()
} }
let mut v = clean_maybe_renamed_item(cx, item, *renamed);
v.drain_filter(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
// it takes priority over the inlined stuff.
!inserted.insert((item.type_(), name))
} else {
false
}
});
v
})); }));
// determine if we should display the inner contents or // determine if we should display the inner contents or
@ -266,66 +259,68 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Life
} }
} }
impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> { fn clean_where_predicate<'tcx>(
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> { predicate: &hir::WherePredicate<'tcx>,
if !self.in_where_clause() { cx: &mut DocContext<'tcx>,
return None; ) -> Option<WherePredicate> {
} if !predicate.in_where_clause() {
Some(match *self { return None;
hir::WherePredicate::BoundPredicate(ref wbp) => {
let bound_params = wbp
.bound_generic_params
.iter()
.map(|param| {
// Higher-ranked params must be lifetimes.
// Higher-ranked lifetimes can't have bounds.
assert_matches!(
param,
hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
);
Lifetime(param.name.ident().name)
})
.collect();
WherePredicate::BoundPredicate {
ty: clean_ty(wbp.bounded_ty, cx),
bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
bound_params,
}
}
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: clean_lifetime(wrp.lifetime, cx),
bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
lhs: clean_ty(wrp.lhs_ty, cx),
rhs: clean_ty(wrp.rhs_ty, cx).into(),
},
})
} }
Some(match *predicate {
hir::WherePredicate::BoundPredicate(ref wbp) => {
let bound_params = wbp
.bound_generic_params
.iter()
.map(|param| {
// Higher-ranked params must be lifetimes.
// Higher-ranked lifetimes can't have bounds.
assert_matches!(
param,
hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
);
Lifetime(param.name.ident().name)
})
.collect();
WherePredicate::BoundPredicate {
ty: clean_ty(wbp.bounded_ty, cx),
bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
bound_params,
}
}
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: clean_lifetime(wrp.lifetime, cx),
bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
lhs: clean_ty(wrp.lhs_ty, cx),
rhs: clean_ty(wrp.rhs_ty, cx).into(),
},
})
} }
impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> { pub(crate) fn clean_predicate<'tcx>(
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> { predicate: ty::Predicate<'tcx>,
let bound_predicate = self.kind(); cx: &mut DocContext<'tcx>,
match bound_predicate.skip_binder() { ) -> Option<WherePredicate> {
ty::PredicateKind::Trait(pred) => { let bound_predicate = predicate.kind();
clean_poly_trait_predicate(bound_predicate.rebind(pred), cx) match bound_predicate.skip_binder() {
} ty::PredicateKind::Trait(pred) => {
ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred), clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::WellFormed(..) => None,
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
} }
ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::WellFormed(..) => None,
ty::PredicateKind::Subtype(..)
| ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
} }
} }
@ -601,7 +596,11 @@ impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
let mut generics = Generics { let mut generics = Generics {
params, params,
where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(), where_predicates: self
.predicates
.iter()
.filter_map(|x| clean_where_predicate(x, cx))
.collect(),
}; };
// Some duplicates are generated for ?Sized bounds between type params and where // Some duplicates are generated for ?Sized bounds between type params and where
@ -702,7 +701,7 @@ fn clean_ty_generics<'tcx>(
if let Some(param_idx) = param_idx { if let Some(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(&param_idx.into()) { if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
let p: WherePredicate = p.clean(cx)?; let p: WherePredicate = clean_predicate(*p, cx)?;
b.extend( b.extend(
p.get_bounds() p.get_bounds()
@ -759,7 +758,7 @@ fn clean_ty_generics<'tcx>(
// Now that `cx.impl_trait_bounds` is populated, we can process // Now that `cx.impl_trait_bounds` is populated, we can process
// remaining predicates which could contain `impl Trait`. // remaining predicates which could contain `impl Trait`.
let mut where_predicates = let mut where_predicates =
where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>(); where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
// Type parameters have a Sized bound by default unless removed with // Type parameters have a Sized bound by default unless removed with
// ?Sized. Scan through the predicates and mark any type parameter with // ?Sized. Scan through the predicates and mark any type parameter with
@ -1962,7 +1961,7 @@ fn clean_maybe_renamed_item<'tcx>(
return clean_extern_crate(item, name, orig_name, cx); return clean_extern_crate(item, name, orig_name, cx);
} }
ItemKind::Use(path, kind) => { ItemKind::Use(path, kind) => {
return clean_use_statement(item, name, path, kind, cx); return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
} }
_ => unreachable!("not yet converted"), _ => unreachable!("not yet converted"),
}; };
@ -2083,6 +2082,7 @@ fn clean_use_statement<'tcx>(
path: &hir::Path<'tcx>, path: &hir::Path<'tcx>,
kind: hir::UseKind, kind: hir::UseKind,
cx: &mut DocContext<'tcx>, cx: &mut DocContext<'tcx>,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
) -> Vec<Item> { ) -> Vec<Item> {
// We need this comparison because some imports (for std types for example) // We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be // are "inserted" as well but directly by the compiler and they should not be
@ -2148,7 +2148,8 @@ fn clean_use_statement<'tcx>(
let inner = if kind == hir::UseKind::Glob { let inner = if kind == hir::UseKind::Glob {
if !denied { if !denied {
let mut visited = FxHashSet::default(); let mut visited = FxHashSet::default();
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited, inlined_names)
{
return items; return items;
} }
} }

View file

@ -1550,6 +1550,15 @@ fn render_impl(
rendering_params: ImplRenderingParameters, rendering_params: ImplRenderingParameters,
) { ) {
for trait_item in &t.items { for trait_item in &t.items {
// Skip over any default trait items that are impossible to call
// (e.g. if it has a `Self: Sized` bound on an unsized type).
if let Some(impl_def_id) = parent.item_id.as_def_id()
&& let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
&& cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
{
continue;
}
let n = trait_item.name; let n = trait_item.name;
if i.items.iter().any(|m| m.name == n) { if i.items.iter().any(|m| m.name == n) {
continue; continue;

View file

@ -119,6 +119,16 @@ where
} }
} }
impl<I, T, U> FromWithTcx<I> for Vec<U>
where
I: IntoIterator<Item = T>,
U: FromWithTcx<T>,
{
fn from_tcx(f: I, tcx: TyCtxt<'_>) -> Vec<U> {
f.into_iter().map(|x| x.into_tcx(tcx)).collect()
}
}
pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
#[rustfmt::skip] #[rustfmt::skip]
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation; let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
@ -130,11 +140,11 @@ impl FromWithTcx<clean::GenericArgs> for GenericArgs {
use clean::GenericArgs::*; use clean::GenericArgs::*;
match args { match args {
AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), args: args.into_vec().into_tcx(tcx),
bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(), bindings: bindings.into_tcx(tcx),
}, },
Parenthesized { inputs, output } => GenericArgs::Parenthesized { Parenthesized { inputs, output } => GenericArgs::Parenthesized {
inputs: inputs.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(), inputs: inputs.into_vec().into_tcx(tcx),
output: output.map(|a| (*a).into_tcx(tcx)), output: output.map(|a| (*a).into_tcx(tcx)),
}, },
} }
@ -145,7 +155,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self { fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
use clean::GenericArg::*; use clean::GenericArg::*;
match arg { match arg {
Lifetime(l) => GenericArg::Lifetime(l.0.to_string()), Lifetime(l) => GenericArg::Lifetime(convert_lifetime(l)),
Type(t) => GenericArg::Type(t.into_tcx(tcx)), Type(t) => GenericArg::Type(t.into_tcx(tcx)),
Const(box c) => GenericArg::Const(c.into_tcx(tcx)), Const(box c) => GenericArg::Const(c.into_tcx(tcx)),
Infer => GenericArg::Infer, Infer => GenericArg::Infer,
@ -177,9 +187,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
use clean::TypeBindingKind::*; use clean::TypeBindingKind::*;
match kind { match kind {
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)), Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
Constraint { bounds } => { Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
}
} }
} }
} }
@ -244,7 +252,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)), TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(tcx)),
MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)), MethodItem(m, _) => ItemEnum::Method(from_function_method(m, true, header.unwrap(), tcx)),
TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)), TyMethodItem(m) => ItemEnum::Method(from_function_method(m, false, header.unwrap(), tcx)),
ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)), ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)), ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
ForeignTypeItem => ItemEnum::ForeignType, ForeignTypeItem => ItemEnum::ForeignType,
@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
} }
TyAssocTypeItem(g, b) => ItemEnum::AssocType { TyAssocTypeItem(g, b) => ItemEnum::AssocType {
generics: (*g).into_tcx(tcx), generics: (*g).into_tcx(tcx),
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), bounds: b.into_tcx(tcx),
default: None, default: None,
}, },
AssocTypeItem(t, b) => ItemEnum::AssocType { AssocTypeItem(t, b) => ItemEnum::AssocType {
generics: t.generics.into_tcx(tcx), generics: t.generics.into_tcx(tcx),
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(), bounds: b.into_tcx(tcx),
default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)), default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
}, },
// `convert_item` early returns `None` for stripped items and keywords. // `convert_item` early returns `None` for stripped items and keywords.
@ -347,15 +355,15 @@ fn convert_abi(a: RustcAbi) -> Abi {
} }
} }
fn convert_lifetime(l: clean::Lifetime) -> String {
l.0.to_string()
}
impl FromWithTcx<clean::Generics> for Generics { impl FromWithTcx<clean::Generics> for Generics {
fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self { fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
Generics { Generics {
params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(), params: generics.params.into_tcx(tcx),
where_predicates: generics where_predicates: generics.where_predicates.into_tcx(tcx),
.where_predicates
.into_iter()
.map(|x| x.into_tcx(tcx))
.collect(),
} }
} }
} }
@ -374,10 +382,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
use clean::GenericParamDefKind::*; use clean::GenericParamDefKind::*;
match kind { match kind {
Lifetime { outlives } => GenericParamDefKind::Lifetime { Lifetime { outlives } => GenericParamDefKind::Lifetime {
outlives: outlives.into_iter().map(|lt| lt.0.to_string()).collect(), outlives: outlives.into_iter().map(convert_lifetime).collect(),
}, },
Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type { Type { did: _, bounds, default, synthetic } => GenericParamDefKind::Type {
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), bounds: bounds.into_tcx(tcx),
default: default.map(|x| (*x).into_tcx(tcx)), default: default.map(|x| (*x).into_tcx(tcx)),
synthetic, synthetic,
}, },
@ -395,7 +403,7 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
match predicate { match predicate {
BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate { BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
type_: ty.into_tcx(tcx), type_: ty.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), bounds: bounds.into_tcx(tcx),
generic_params: bound_params generic_params: bound_params
.into_iter() .into_iter()
.map(|x| GenericParamDef { .map(|x| GenericParamDef {
@ -405,8 +413,8 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
.collect(), .collect(),
}, },
RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
lifetime: lifetime.0.to_string(), lifetime: convert_lifetime(lifetime),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), bounds: bounds.into_tcx(tcx),
}, },
EqPredicate { lhs, rhs } => { EqPredicate { lhs, rhs } => {
WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) } WherePredicate::EqPredicate { lhs: lhs.into_tcx(tcx), rhs: rhs.into_tcx(tcx) }
@ -424,11 +432,11 @@ impl FromWithTcx<clean::GenericBound> for GenericBound {
let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx); let trait_ = clean::Type::Path { path: trait_ }.into_tcx(tcx);
GenericBound::TraitBound { GenericBound::TraitBound {
trait_, trait_,
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), generic_params: generic_params.into_tcx(tcx),
modifier: from_trait_bound_modifier(modifier), modifier: from_trait_bound_modifier(modifier),
} }
} }
Outlives(lifetime) => GenericBound::Outlives(lifetime.0.to_string()), Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)),
} }
} }
} }
@ -447,8 +455,8 @@ pub(crate) fn from_trait_bound_modifier(
impl FromWithTcx<clean::Type> for Type { impl FromWithTcx<clean::Type> for Type {
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self { fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
use clean::Type::{ use clean::Type::{
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
QPath, RawPointer, Slice, Tuple, RawPointer, Slice, Tuple,
}; };
match ty { match ty {
@ -458,40 +466,24 @@ impl FromWithTcx<clean::Type> for Type {
args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))), args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: Vec::new(), param_names: Vec::new(),
}, },
DynTrait(mut bounds, lt) => { clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
let first_trait = bounds.remove(0).trait_; lifetime: lt.map(convert_lifetime),
traits: bounds.into_tcx(tcx),
Type::ResolvedPath { }),
name: first_trait.whole_name(),
id: from_item_id(first_trait.def_id().into(), tcx),
args: first_trait
.segments
.last()
.map(|args| Box::new(args.clone().args.into_tcx(tcx))),
param_names: bounds
.into_iter()
.map(|t| {
clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
})
.chain(lt.map(clean::GenericBound::Outlives))
.map(|bound| bound.into_tcx(tcx))
.collect(),
}
}
Generic(s) => Type::Generic(s.to_string()), Generic(s) => Type::Generic(s.to_string()),
Primitive(p) => Type::Primitive(p.as_sym().to_string()), Primitive(p) => Type::Primitive(p.as_sym().to_string()),
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))), BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()), Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s }, Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s },
ImplTrait(g) => Type::ImplTrait(g.into_iter().map(|x| x.into_tcx(tcx)).collect()), ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
Infer => Type::Infer, Infer => Type::Infer,
RawPointer(mutability, type_) => Type::RawPointer { RawPointer(mutability, type_) => Type::RawPointer {
mutable: mutability == ast::Mutability::Mut, mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)), type_: Box::new((*type_).into_tcx(tcx)),
}, },
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
lifetime: lifetime.map(|l| l.0.to_string()), lifetime: lifetime.map(convert_lifetime),
mutable: mutability == ast::Mutability::Mut, mutable: mutability == ast::Mutability::Mut,
type_: Box::new((*type_).into_tcx(tcx)), type_: Box::new((*type_).into_tcx(tcx)),
}, },
@ -528,7 +520,7 @@ impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
async_: false, async_: false,
abi: convert_abi(abi), abi: convert_abi(abi),
}, },
generic_params: generic_params.into_iter().map(|x| x.into_tcx(tcx)).collect(), generic_params: generic_params.into_tcx(tcx),
decl: decl.into_tcx(tcx), decl: decl.into_tcx(tcx),
} }
} }
@ -562,16 +554,28 @@ impl FromWithTcx<clean::Trait> for Trait {
is_unsafe, is_unsafe,
items: ids(items, tcx), items: ids(items, tcx),
generics: generics.into_tcx(tcx), generics: generics.into_tcx(tcx),
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(), bounds: bounds.into_tcx(tcx),
implementations: Vec::new(), // Added in JsonRenderer::item implementations: Vec::new(), // Added in JsonRenderer::item
} }
} }
} }
impl FromWithTcx<Box<clean::Impl>> for Impl { impl FromWithTcx<clean::PolyTrait> for PolyTrait {
fn from_tcx(impl_: Box<clean::Impl>, tcx: TyCtxt<'_>) -> Self { fn from_tcx(
clean::PolyTrait { trait_, generic_params }: clean::PolyTrait,
tcx: TyCtxt<'_>,
) -> Self {
PolyTrait {
trait_: clean::Type::Path { path: trait_ }.into_tcx(tcx),
generic_params: generic_params.into_tcx(tcx),
}
}
}
impl FromWithTcx<clean::Impl> for Impl {
fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
let provided_trait_methods = impl_.provided_trait_methods(tcx); let provided_trait_methods = impl_.provided_trait_methods(tcx);
let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = *impl_; let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON? // FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx)); let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
// FIXME: use something like ImplKind in JSON? // FIXME: use something like ImplKind in JSON?
@ -730,10 +734,7 @@ impl FromWithTcx<Box<clean::Typedef>> for Typedef {
impl FromWithTcx<clean::OpaqueTy> for OpaqueTy { impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self { fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
OpaqueTy { OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
generics: opaque.generics.into_tcx(tcx),
}
} }
} }
@ -749,10 +750,7 @@ impl FromWithTcx<clean::Static> for Static {
impl FromWithTcx<clean::TraitAlias> for TraitAlias { impl FromWithTcx<clean::TraitAlias> for TraitAlias {
fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self { fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
TraitAlias { TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) }
generics: alias.generics.into_tcx(tcx),
params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
}
} }
} }

View file

@ -9,7 +9,7 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// rustdoc format-version. /// rustdoc format-version.
pub const FORMAT_VERSION: u32 = 16; pub const FORMAT_VERSION: u32 = 17;
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
/// about the language items in the local crate, as well as info about external items to allow /// about the language items in the local crate, as well as info about external items to allow
@ -115,6 +115,35 @@ pub enum Visibility {
}, },
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DynTrait {
/// All the traits implemented. One of them is the vtable, and the rest must be auto traits.
pub traits: Vec<PolyTrait>,
/// The lifetime of the whole dyn object
/// ```text
/// dyn Debug + 'static
/// ^^^^^^^
/// |
/// this part
/// ```
pub lifetime: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
/// A trait and potential HRTBs
pub struct PolyTrait {
#[serde(rename = "trait")]
pub trait_: Type,
/// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```text
/// dyn for<'a> Fn() -> &'a i32"
/// ^^^^^^^
/// |
/// this part
/// ```
pub generic_params: Vec<GenericParamDef>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum GenericArgs { pub enum GenericArgs {
@ -395,7 +424,7 @@ pub enum WherePredicate {
type_: Type, type_: Type,
bounds: Vec<GenericBound>, bounds: Vec<GenericBound>,
/// Used for Higher-Rank Trait Bounds (HRTBs) /// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain /// ```text
/// where for<'a> &'a T: Iterator," /// where for<'a> &'a T: Iterator,"
/// ^^^^^^^ /// ^^^^^^^
/// | /// |
@ -420,7 +449,7 @@ pub enum GenericBound {
#[serde(rename = "trait")] #[serde(rename = "trait")]
trait_: Type, trait_: Type,
/// Used for Higher-Rank Trait Bounds (HRTBs) /// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain /// ```text
/// where F: for<'a, 'b> Fn(&'a u8, &'b u8) /// where F: for<'a, 'b> Fn(&'a u8, &'b u8)
/// ^^^^^^^^^^^ /// ^^^^^^^^^^^
/// | /// |
@ -458,6 +487,7 @@ pub enum Type {
args: Option<Box<GenericArgs>>, args: Option<Box<GenericArgs>>,
param_names: Vec<GenericBound>, param_names: Vec<GenericBound>,
}, },
DynTrait(DynTrait),
/// Parameterized types /// Parameterized types
Generic(String), Generic(String),
/// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
@ -505,7 +535,7 @@ pub enum Type {
pub struct FunctionPointer { pub struct FunctionPointer {
pub decl: FnDecl, pub decl: FnDecl,
/// Used for Higher-Rank Trait Bounds (HRTBs) /// Used for Higher-Rank Trait Bounds (HRTBs)
/// ```plain /// ```text
/// for<'c> fn(val: &'c i32) -> i32 /// for<'c> fn(val: &'c i32) -> i32
/// ^^^^^^^ /// ^^^^^^^
/// | /// |

View file

@ -1,8 +1,13 @@
// ignore-tidy-linelength // ignore-tidy-linelength
use std::fmt::Debug;
// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1 // @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items[*]" 3
// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id" // @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id"
// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen // @set ref_fn = - "$.index[*][?(@.name=='RefFn')].id"
// @set weird_order = - "$.index[*][?(@.name=='WeirdOrder')].id"
// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $sync_int_gen
// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $ref_fn
// @has - "$.index[*][?(@.name=='dyn')].inner.items[*]" $weird_order
// @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\" // @is - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}' // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
@ -10,12 +15,35 @@
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" [] // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" []
// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1 // @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"dyn_trait\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.lifetime" \"\'static\"
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\" // @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 3
// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3 // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].generic_params" []
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].generic_params" []
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].generic_params" []
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}" // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Fn"'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}' // @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Send"'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[2].trait.inner.name" '"Sync"'
// @is - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>; pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
// @is - "$.index[*][?(@.name=='RefFn')].kind" \"typedef\"
// @is - "$.index[*][?(@.name=='RefFn')].inner.generics" '{"params": [{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"}],"where_predicates": []}'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.mutable" 'false'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.lifetime" "\"'a\""
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.kind" '"dyn_trait"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.lifetime" null
// @count - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[*]" 1
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.kind" '"resolved_path"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.name" '"Fn"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.inputs[0].inner.lifetime" "\"'b\""
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='RefFn')].inner.type.inner.type.inner.traits[0].trait.inner.args.parenthesized.output.inner.lifetime" "\"'b\""
pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32;
// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[0].trait.inner.name" '"Send"'
// @is - "$.index[*][?(@.name=='WeirdOrder')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[1].trait.inner.name" '"Debug"'
pub type WeirdOrder = Box<dyn Send + Debug>;

View file

@ -0,0 +1,26 @@
// ignore-tidy-linelength
// @has hrtb.json
// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.type" '{"inner": "F","kind": "generic"}'
// @is - "$.index[*][?(@.name=='genfn')].inner.generics.where_predicates[0].bound_predicate.generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
pub fn genfn<F>(f: F)
where
for<'a, 'b> F: Fn(&'a i32, &'b i32),
{
let zero = 0;
f(&zero, &zero);
}
// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
// @is - "$.index[*][?(@.name=='dynfn')].inner.generics" '{"params": [], "where_predicates": []}'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].kind" '"borrowed_ref"'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.kind" '"dyn_trait"'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.lifetime" null
// @count - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[*]" 1
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]'
// @is - "$.index[*][?(@.name=='dynfn')].inner.decl.inputs[0][1].inner.type.inner.traits[0].trait.inner.name" '"Fn"'
pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) {
let zero = 0;
f(&zero, &zero);
}

View file

@ -0,0 +1,13 @@
#![crate_name="first"]
pub mod prelude {
pub use crate::Bot;
}
pub struct Bot;
impl Bot {
pub fn new() -> Bot {
Bot
}
}

View file

@ -0,0 +1,21 @@
// Regression test for #100143
use std::iter::Peekable;
pub struct Span<F: Fn(&i32)> {
inner: Peekable<ConditionalIterator<F>>,
}
pub struct ConditionalIterator<F> {
f: F,
}
// @has 'fn_bound/struct.ConditionalIterator.html' '//h3[@class="code-header in-band"]' 'impl<F: Fn(&i32)> Iterator for ConditionalIterator<F>'
impl<F: Fn(&i32)> Iterator for ConditionalIterator<F> {
type Item = ();
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}

View file

@ -0,0 +1,20 @@
#![crate_name = "foo"]
// Check that default trait items that are impossible to satisfy
pub trait Foo {
fn needs_sized(&self)
where
Self: Sized,
{}
fn no_needs_sized(&self) {}
}
// @!has foo/struct.Bar.html '//*[@id="method.needs_sized"]//h4[@class="code-header"]' \
// "fn needs_sized"
// @has foo/struct.Bar.html '//*[@id="method.no_needs_sized"]//h4[@class="code-header"]' \
// "fn no_needs_sized"
pub struct Bar([u8]);
impl Foo for Bar {}

View file

@ -0,0 +1,14 @@
// aux-build:issue-100204-aux.rs
// build-aux-docs
// ignore-cross-compile
#![crate_name="second"]
extern crate first;
pub mod prelude {}
// @has first/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
// @has second/struct.Bot.html '//h4[@class="code-header"]' 'pub fn new() -> Bot'
#[doc(inline)]
pub use first::*;

View file

@ -57,13 +57,11 @@ LL | a + 1
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:33:1 --> $DIR/naked-functions.rs:33:1
| |
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 { LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | a + 1 LL |
| | ----- non-asm is unsupported in naked functions LL | a + 1
LL | | | ----- non-asm is unsupported in naked functions
LL | | }
| |_^
error: referencing function parameters is not allowed in naked functions error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:42:31 --> $DIR/naked-functions.rs:42:31
@ -82,12 +80,11 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:48:1 --> $DIR/naked-functions.rs:48:1
| |
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 { LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | (|| a + 1)() LL |
| | ------------ non-asm is unsupported in naked functions LL | (|| a + 1)()
LL | | } | ------------ non-asm is unsupported in naked functions
| |_^
error[E0787]: only `const` and `sym` operands are supported in naked functions error[E0787]: only `const` and `sym` operands are supported in naked functions
--> $DIR/naked-functions.rs:65:10 --> $DIR/naked-functions.rs:65:10
@ -124,30 +121,25 @@ LL | sym G, options(noreturn),
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:54:1 --> $DIR/naked-functions.rs:54:1
| |
LL | / pub unsafe extern "C" fn unsupported_operands() { LL | pub unsafe extern "C" fn unsupported_operands() {
LL | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | let mut a = 0usize; LL |
| | ------------------- non-asm is unsupported in naked functions LL | let mut a = 0usize;
LL | | let mut b = 0usize; | ------------------- non-asm is unsupported in naked functions
| | ------------------- non-asm is unsupported in naked functions LL | let mut b = 0usize;
LL | | let mut c = 0usize; | ------------------- non-asm is unsupported in naked functions
| | ------------------- non-asm is unsupported in naked functions LL | let mut c = 0usize;
LL | | let mut d = 0usize; | ------------------- non-asm is unsupported in naked functions
| | ------------------- non-asm is unsupported in naked functions LL | let mut d = 0usize;
LL | | let mut e = 0usize; | ------------------- non-asm is unsupported in naked functions
| | ------------------- non-asm is unsupported in naked functions LL | let mut e = 0usize;
... | | ------------------- non-asm is unsupported in naked functions
LL | | );
LL | | }
| |_^
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:77:1 --> $DIR/naked-functions.rs:77:1
| |
LL | / pub extern "C" fn missing_assembly() { LL | pub extern "C" fn missing_assembly() {
LL | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | }
| |_^
error[E0787]: asm in naked functions must use `noreturn` option error[E0787]: asm in naked functions must use `noreturn` option
--> $DIR/naked-functions.rs:84:5 --> $DIR/naked-functions.rs:84:5
@ -185,20 +177,17 @@ LL | asm!("", options(noreturn));
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:82:1 --> $DIR/naked-functions.rs:82:1
| |
LL | / pub extern "C" fn too_many_asm_blocks() { LL | pub extern "C" fn too_many_asm_blocks() {
LL | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | asm!(""); ...
LL | | LL | asm!("");
LL | | asm!(""); | -------- multiple asm blocks are unsupported in naked functions
| | -------- multiple asm blocks are unsupported in naked functions LL |
LL | | LL | asm!("");
LL | | asm!(""); | -------- multiple asm blocks are unsupported in naked functions
| | -------- multiple asm blocks are unsupported in naked functions LL |
LL | | LL | asm!("", options(noreturn));
LL | | asm!("", options(noreturn)); | --------------------------- multiple asm blocks are unsupported in naked functions
| | --------------------------- multiple asm blocks are unsupported in naked functions
LL | | }
| |_^
error: referencing function parameters is not allowed in naked functions error: referencing function parameters is not allowed in naked functions
--> $DIR/naked-functions.rs:97:11 --> $DIR/naked-functions.rs:97:11
@ -211,13 +200,11 @@ LL | *&y
error[E0787]: naked functions must contain a single asm block error[E0787]: naked functions must contain a single asm block
--> $DIR/naked-functions.rs:95:5 --> $DIR/naked-functions.rs:95:5
| |
LL | / pub extern "C" fn inner(y: usize) -> usize { LL | pub extern "C" fn inner(y: usize) -> usize {
LL | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | *&y LL |
| | --- non-asm is unsupported in naked functions LL | *&y
LL | | | --- non-asm is unsupported in naked functions
LL | | }
| |_____^
error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags` error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
--> $DIR/naked-functions.rs:105:5 --> $DIR/naked-functions.rs:105:5
@ -249,18 +236,18 @@ LL | asm!("", options(noreturn, may_unwind));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: Rust ABI is unsupported in naked functions warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:124:15 --> $DIR/naked-functions.rs:124:1
| |
LL | pub unsafe fn default_abi() { LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
= note: `#[warn(undefined_naked_function_abi)]` on by default = note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions warning: Rust ABI is unsupported in naked functions
--> $DIR/naked-functions.rs:130:15 --> $DIR/naked-functions.rs:130:1
| |
LL | pub unsafe fn rust_abi() { LL | pub unsafe fn rust_abi() {
| ^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^
error: naked functions cannot be inlined error: naked functions cannot be inlined
--> $DIR/naked-functions.rs:170:1 --> $DIR/naked-functions.rs:170:1

View file

@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
fn main() { fn main() {
let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter(); let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
//~^ ERROR type mismatch //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
} }

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == i32` error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `i32`, but it yields `u32`
--> $DIR/associated-types-overridden-binding-2.rs:6:43 --> $DIR/associated-types-overridden-binding-2.rs:6:43
| |
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter(); LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();

View file

@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 {
return 0u8; return 0u8;
}; };
let _: &dyn Future<Output = ()> = &block; let _: &dyn Future<Output = ()> = &block;
//~^ ERROR type mismatch //~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
} }
async fn return_targets_async_block_not_async_fn() -> u8 { async fn return_targets_async_block_not_async_fn() -> u8 {
@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
return 0u8; return 0u8;
}; };
let _: &dyn Future<Output = ()> = &block; let _: &dyn Future<Output = ()> = &block;
//~^ ERROR type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` //~^ ERROR expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
} }
fn no_break_in_async_block() { fn no_break_in_async_block() {
@ -42,7 +42,9 @@ fn no_break_in_async_block_even_with_outer_loop() {
} }
struct MyErr; struct MyErr;
fn err() -> Result<u8, MyErr> { Err(MyErr) } fn err() -> Result<u8, MyErr> {
Err(MyErr)
}
fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> { fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
//~^ ERROR mismatched types //~^ ERROR mismatched types

View file

@ -31,7 +31,7 @@ LL | |
LL | | } LL | | }
| |_^ expected `u8`, found `()` | |_^ expected `u8`, found `()`
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:26:39 --> $DIR/async-block-control-flow-static-semantics.rs:26:39
| |
LL | let _: &dyn Future<Output = ()> = &block; LL | let _: &dyn Future<Output = ()> = &block;
@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
| | | |
| implicitly returns `()` as its body has no tail or `return` expression | implicitly returns `()` as its body has no tail or `return` expression
error[E0271]: type mismatch resolving `<impl Future<Output = u8> as Future>::Output == ()` error[E0271]: expected `impl Future<Output = u8>` to be a future that resolves to `()`, but it resolves to `u8`
--> $DIR/async-block-control-flow-static-semantics.rs:17:39 --> $DIR/async-block-control-flow-static-semantics.rs:17:39
| |
LL | let _: &dyn Future<Output = ()> = &block; LL | let _: &dyn Future<Output = ()> = &block;
@ -56,7 +56,7 @@ LL | let _: &dyn Future<Output = ()> = &block;
= note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>` = note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:47:44 --> $DIR/async-block-control-flow-static-semantics.rs:49:44
| |
LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> { LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
| ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()` | ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
found unit type `()` found unit type `()`
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:56:50 --> $DIR/async-block-control-flow-static-semantics.rs:58:50
| |
LL | fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> { LL | fn rethrow_targets_async_block_not_async_fn() -> Result<u8, MyErr> {
| ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()` | ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`

View file

@ -6,9 +6,9 @@
enum Eu64 { enum Eu64 {
//~^ ERROR discriminant value `0` assigned more than once //~^ ERROR discriminant value `0` assigned more than once
Au64 = 0, Au64 = 0,
//~^NOTE first assignment of `0` //~^NOTE `0` assigned here
Bu64 = 0x8000_0000_0000_0000 Bu64 = 0x8000_0000_0000_0000
//~^NOTE second assignment of `0` (overflowed from `9223372036854775808`) //~^NOTE `0` (overflowed from `9223372036854775808`) assigned here
} }
fn main() {} fn main() {}

View file

@ -5,10 +5,10 @@ LL | enum Eu64 {
| ^^^^^^^^^ | ^^^^^^^^^
LL | LL |
LL | Au64 = 0, LL | Au64 = 0,
| - first assignment of `0` | - `0` assigned here
LL | LL |
LL | Bu64 = 0x8000_0000_0000_0000 LL | Bu64 = 0x8000_0000_0000_0000
| --------------------- second assignment of `0` (overflowed from `9223372036854775808`) | --------------------- `0` (overflowed from `9223372036854775808`) assigned here
error: aborting due to previous error error: aborting due to previous error

View file

@ -1,9 +1,9 @@
enum Enum { enum Enum {
//~^ ERROR discriminant value `3` assigned more than once //~^ ERROR discriminant value `3` assigned more than once
P = 3, P = 3,
//~^ NOTE first assignment of `3` //~^ NOTE `3` assigned here
X = 3, X = 3,
//~^ NOTE second assignment of `3` //~^ NOTE `3` assigned here
Y = 5 Y = 5
} }
@ -11,20 +11,43 @@ enum Enum {
enum EnumOverflowRepr { enum EnumOverflowRepr {
//~^ ERROR discriminant value `1` assigned more than once //~^ ERROR discriminant value `1` assigned more than once
P = 257, P = 257,
//~^ NOTE first assignment of `1` (overflowed from `257`) //~^ NOTE `1` (overflowed from `257`) assigned here
X = 513, X = 513,
//~^ NOTE second assignment of `1` (overflowed from `513`) //~^ NOTE `1` (overflowed from `513`) assigned here
} }
#[repr(i8)] #[repr(i8)]
enum NegDisEnum { enum NegDisEnum {
//~^ ERROR discriminant value `-1` assigned more than once //~^ ERROR discriminant value `-1` assigned more than once
First = -1, First = -1,
//~^ NOTE first assignment of `-1` //~^ NOTE `-1` assigned here
Second = -2, Second = -2,
//~^ NOTE assigned discriminant for `Last` was incremented from this discriminant //~^ NOTE discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
Last, Last,
//~^ NOTE second assignment of `-1` //~^ NOTE `-1` assigned here
}
enum MultipleDuplicates {
//~^ ERROR discriminant value `0` assigned more than once
//~^^ ERROR discriminant value `-2` assigned more than once
V0,
//~^ NOTE `0` assigned here
V1 = 0,
//~^ NOTE `0` assigned here
V2,
V3,
V4 = 0,
//~^ NOTE `0` assigned here
V5 = -2,
//~^ NOTE discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
//~^^ NOTE `-2` assigned here
V6,
V7,
//~^ NOTE `0` assigned here
V8 = -3,
//~^ NOTE discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
V9,
//~^ NOTE `-2` assigned here
} }
fn main() { fn main() {

View file

@ -5,10 +5,10 @@ LL | enum Enum {
| ^^^^^^^^^ | ^^^^^^^^^
LL | LL |
LL | P = 3, LL | P = 3,
| - first assignment of `3` | - `3` assigned here
LL | LL |
LL | X = 3, LL | X = 3,
| - second assignment of `3` | - `3` assigned here
error[E0081]: discriminant value `1` assigned more than once error[E0081]: discriminant value `1` assigned more than once
--> $DIR/E0081.rs:11:1 --> $DIR/E0081.rs:11:1
@ -17,10 +17,10 @@ LL | enum EnumOverflowRepr {
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
LL | LL |
LL | P = 257, LL | P = 257,
| --- first assignment of `1` (overflowed from `257`) | --- `1` (overflowed from `257`) assigned here
LL | LL |
LL | X = 513, LL | X = 513,
| --- second assignment of `1` (overflowed from `513`) | --- `1` (overflowed from `513`) assigned here
error[E0081]: discriminant value `-1` assigned more than once error[E0081]: discriminant value `-1` assigned more than once
--> $DIR/E0081.rs:20:1 --> $DIR/E0081.rs:20:1
@ -29,14 +29,50 @@ LL | enum NegDisEnum {
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
LL | LL |
LL | First = -1, LL | First = -1,
| -- first assignment of `-1` | -- `-1` assigned here
LL | LL |
LL | Second = -2, LL | Second = -2,
| ----------- assigned discriminant for `Last` was incremented from this discriminant | ----------- discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
LL | LL |
LL | Last, LL | Last,
| ---- second assignment of `-1` | ---- `-1` assigned here
error: aborting due to 3 previous errors error[E0081]: discriminant value `0` assigned more than once
--> $DIR/E0081.rs:30:1
|
LL | enum MultipleDuplicates {
| ^^^^^^^^^^^^^^^^^^^^^^^
...
LL | V0,
| -- `0` assigned here
LL |
LL | V1 = 0,
| - `0` assigned here
...
LL | V4 = 0,
| - `0` assigned here
LL |
LL | V5 = -2,
| ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
...
LL | V7,
| -- `0` assigned here
error[E0081]: discriminant value `-2` assigned more than once
--> $DIR/E0081.rs:30:1
|
LL | enum MultipleDuplicates {
| ^^^^^^^^^^^^^^^^^^^^^^^
...
LL | V5 = -2,
| -- `-2` assigned here
...
LL | V8 = -3,
| ------- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
LL |
LL | V9,
| -- `-2` assigned here
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0081`. For more information about this error, try `rustc --explain E0081`.

View file

@ -38,9 +38,13 @@ fn main() {
let v = Unit2.m( let v = Unit2.m(
//~^ ERROR type mismatch //~^ ERROR type mismatch
L { L {
//~^ ERROR type mismatch //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
f : |x| { drop(x); Unit4 } f: |x| {
}); drop(x);
Unit4
},
},
);
} }
impl<'a> Ty<'a> for Unit2 { impl<'a> Ty<'a> for Unit2 {

View file

@ -1,8 +1,8 @@
error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:38:19 --> $DIR/issue-62203-hrtb-ice.rs:38:19
| |
LL | let v = Unit2.m( LL | let v = Unit2.m(
| ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V` | ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
| |
note: expected this to be `<_ as Ty<'_>>::V` note: expected this to be `<_ as Ty<'_>>::V`
--> $DIR/issue-62203-hrtb-ice.rs:21:14 --> $DIR/issue-62203-hrtb-ice.rs:21:14
@ -22,7 +22,7 @@ LL | where
LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>, LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m` | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3` error[E0271]: expected `[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]` to be a closure that returns `Unit3`, but it returns `Unit4`
--> $DIR/issue-62203-hrtb-ice.rs:40:9 --> $DIR/issue-62203-hrtb-ice.rs:40:9
| |
LL | let v = Unit2.m( LL | let v = Unit2.m(
@ -30,11 +30,14 @@ LL | let v = Unit2.m(
LL | LL |
LL | / L { LL | / L {
LL | | LL | |
LL | | f : |x| { drop(x); Unit4 } LL | | f: |x| {
LL | | }); LL | | drop(x);
LL | | Unit4
LL | | },
LL | | },
| |_________^ expected struct `Unit3`, found struct `Unit4` | |_________^ expected struct `Unit3`, found struct `Unit4`
| |
note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>` note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19]>`
--> $DIR/issue-62203-hrtb-ice.rs:17:16 --> $DIR/issue-62203-hrtb-ice.rs:17:16
| |
LL | impl<'a, A, T> T0<'a, A> for L<T> LL | impl<'a, A, T> T0<'a, A> for L<T>

View file

@ -7,7 +7,7 @@ type F = impl core::future::Future<Output = u8>;
struct Bug { struct Bug {
V1: [(); { V1: [(); {
fn concrete_use() -> F { fn concrete_use() -> F {
//~^ ERROR type mismatch //~^ ERROR expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
async {} async {}
} }
let f: F = async { 1 }; let f: F = async { 1 };

View file

@ -16,7 +16,7 @@ LL | let f: F = async { 1 };
LL | }], LL | }],
| - value is dropped here | - value is dropped here
error[E0271]: type mismatch resolving `<impl Future<Output = ()> as Future>::Output == u8` error[E0271]: expected `impl Future<Output = ()>` to be a future that resolves to `u8`, but it resolves to `()`
--> $DIR/issue-78722.rs:9:30 --> $DIR/issue-78722.rs:9:30
| |
LL | fn concrete_use() -> F { LL | fn concrete_use() -> F {

View file

@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 {
const fn return_ty_mismatch() { const fn return_ty_mismatch() {
const_eval_select((1,), foo, bar); const_eval_select((1,), foo, bar);
//~^ ERROR type mismatch //~^ ERROR expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
} }
const fn args_ty_mismatch() { const fn args_ty_mismatch() {

View file

@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select`
LL | G: FnOnce<ARG, Output = RET> + ~const Destruct, LL | G: FnOnce<ARG, Output = RET> + ~const Destruct,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32` error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool`
--> $DIR/const-eval-select-bad.rs:29:5 --> $DIR/const-eval-select-bad.rs:29:5
| |
LL | const_eval_select((1,), foo, bar); LL | const_eval_select((1,), foo, bar);

View file

@ -1,16 +0,0 @@
const N: isize = 1;
enum Foo {
//~^ ERROR discriminant value `1` assigned more than once
//~| ERROR discriminant value `1` assigned more than once
//~| ERROR discriminant value `1` assigned more than once
A = 1,
B = 1,
C = 0,
D,
E = N,
}
fn main() {}

View file

@ -1,40 +0,0 @@
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | enum Foo {
| ^^^^^^^^
...
LL | A = 1,
| - first assignment of `1`
LL | B = 1,
| - second assignment of `1`
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | enum Foo {
| ^^^^^^^^
...
LL | A = 1,
| - first assignment of `1`
LL | B = 1,
LL | C = 0,
| ----- assigned discriminant for `D` was incremented from this discriminant
LL | D,
| - second assignment of `1`
error[E0081]: discriminant value `1` assigned more than once
--> $DIR/issue-15524.rs:3:1
|
LL | enum Foo {
| ^^^^^^^^
...
LL | A = 1,
| - first assignment of `1`
...
LL | E = N,
| - second assignment of `1`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0081`.

View file

@ -3,12 +3,13 @@ use std::vec::IntoIter;
pub fn get_tok(it: &mut IntoIter<u8>) { pub fn get_tok(it: &mut IntoIter<u8>) {
let mut found_e = false; let mut found_e = false;
let temp: Vec<u8> = it.take_while(|&x| { let temp: Vec<u8> = it
found_e = true; .take_while(|&x| {
false found_e = true;
}) false
})
.cloned() .cloned()
//~^ ERROR type mismatch resolving //~^ ERROR to be an iterator that yields `&_`, but it yields `u8`
.collect(); //~ ERROR the method .collect(); //~ ERROR the method
} }

View file

@ -1,5 +1,5 @@
error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_` error[E0271]: expected `TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>` to be an iterator that yields `&_`, but it yields `u8`
--> $DIR/issue-31173.rs:10:10 --> $DIR/issue-31173.rs:11:10
| |
LL | .cloned() LL | .cloned()
| ^^^^^^ expected reference, found `u8` | ^^^^^^ expected reference, found `u8`
@ -12,11 +12,11 @@ note: required by a bound in `cloned`
LL | Self: Sized + Iterator<Item = &'a T>, LL | Self: Sized + Iterator<Item = &'a T>,
| ^^^^^^^^^^^^ required by this bound in `cloned` | ^^^^^^^^^^^^ required by this bound in `cloned`
error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>`, but its trait bounds were not satisfied
--> $DIR/issue-31173.rs:12:10 --> $DIR/issue-31173.rs:13:10
| |
LL | .collect(); LL | .collect();
| ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds | ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>` due to unsatisfied trait bounds
| |
::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
| |
@ -29,10 +29,10 @@ LL | pub struct TakeWhile<I, P> {
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_` | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
| |
= note: the following trait bounds were not satisfied: = note: the following trait bounds were not satisfied:
`<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_` `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]> as Iterator>::Item = &_`
which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
`Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator` which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:7:21: 7:25]>>: Iterator`
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View file

@ -3,7 +3,7 @@
use std::collections::HashMap; use std::collections::HashMap;
fn main() { fn main() {
for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
//~^ ERROR type mismatch //~^ ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
//~| ERROR type mismatch //~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
} }

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_` error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:36 --> $DIR/issue-33941.rs:6:36
| |
LL | for _ in HashMap::new().iter().cloned() {} LL | for _ in HashMap::new().iter().cloned() {}
@ -12,7 +12,7 @@ note: required by a bound in `cloned`
LL | Self: Sized + Iterator<Item = &'a T>, LL | Self: Sized + Iterator<Item = &'a T>,
| ^^^^^^^^^^^^ required by this bound in `cloned` | ^^^^^^^^^^^^ required by this bound in `cloned`
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_` error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14 --> $DIR/issue-33941.rs:6:14
| |
LL | for _ in HashMap::new().iter().cloned() {} LL | for _ in HashMap::new().iter().cloned() {}
@ -23,7 +23,7 @@ LL | for _ in HashMap::new().iter().cloned() {}
= note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` = note: required because of the requirements on the impl of `Iterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
= note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` = note: required because of the requirements on the impl of `IntoIterator` for `Cloned<std::collections::hash_map::Iter<'_, _, _>>`
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as Iterator>::Item == &_` error[E0271]: expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
--> $DIR/issue-33941.rs:6:14 --> $DIR/issue-33941.rs:6:14
| |
LL | for _ in HashMap::new().iter().cloned() {} LL | for _ in HashMap::new().iter().cloned() {}

View file

@ -0,0 +1,18 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
#![feature(proc_macro_quote)]
extern crate proc_macro;
use proc_macro::{quote, Ident, Span, TokenStream, TokenTree};
#[proc_macro_attribute]
pub fn struct_with_bound(_: TokenStream, _: TokenStream) -> TokenStream {
let crate_ident = TokenTree::Ident(Ident::new("crate", Span::call_site()));
let trait_ident = TokenTree::Ident(Ident::new("MyTrait", Span::call_site()));
quote!(
struct Foo<T: $crate_ident::$trait_ident> {}
)
}

View file

@ -0,0 +1,16 @@
#[issue_100199::struct_with_bound] //~ ERROR cannot find trait `MyTrait` in the crate root
struct Foo {}
// The above must be on the first line so that it's span points to pos 0.
// This used to trigger an ICE because the diagnostic emitter would get
// an unexpected dummy span (lo == 0 == hi) while attempting to print a
// suggestion.
// aux-build: issue-100199.rs
extern crate issue_100199;
mod traits {
pub trait MyTrait {}
}
fn main() {}

View file

@ -0,0 +1,15 @@
error[E0405]: cannot find trait `MyTrait` in the crate root
--> $DIR/issue-100199.rs:1:1
|
LL | #[issue_100199::struct_with_bound]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in the crate root
|
= note: this error originates in the attribute macro `issue_100199::struct_with_bound` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this trait
|
LL | use traits::MyTrait;
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0405`.

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()` error[E0271]: expected `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to be a closure that returns `()`, but it returns `!`
--> $DIR/fallback-closure-wrap.rs:18:31 --> $DIR/fallback-closure-wrap.rs:18:31
| |
LL | let error = Closure::wrap(Box::new(move || { LL | let error = Closure::wrap(Box::new(move || {

View file

@ -16,7 +16,7 @@ use std::marker::PhantomData;
fn main() { fn main() {
let error = Closure::wrap(Box::new(move || { let error = Closure::wrap(Box::new(move || {
//[fallback]~^ ERROR type mismatch resolving //[fallback]~^ to be a closure that returns `()`, but it returns `!`
panic!("Can't connect to server."); panic!("Can't connect to server.");
}) as Box<dyn FnMut()>); }) as Box<dyn FnMut()>);
} }

View file

@ -0,0 +1,10 @@
// run-rustfix
fn main() {
match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
Some(1) => {}
// hello
Some(_) => {}
None => todo!()
}
}

View file

@ -0,0 +1,9 @@
// run-rustfix
fn main() {
match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
Some(1) => {}
// hello
Some(_) => {}
}
}

View file

@ -0,0 +1,24 @@
error[E0004]: non-exhaustive patterns: `None` not covered
--> $DIR/suggest-adding-appropriate-missing-pattern-excluding-comments.rs:4:11
|
LL | match Some(1) {
| ^^^^^^^ pattern `None` not covered
|
note: `Option<i32>` defined here
--> $SRC_DIR/core/src/option.rs:LL:COL
|
LL | pub enum Option<T> {
| ------------------
...
LL | None,
| ^^^^ not covered
= note: the matched value is of type `Option<i32>`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
LL ~ Some(_) => {}
LL + None => todo!()
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0004`.

View file

@ -0,0 +1,19 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub fn cause_ice(_: TokenStream) -> TokenStream {
"
enum IceCause {
Variant,
}
pub use IceCause::Variant;
".parse().unwrap()
}

View file

@ -0,0 +1,10 @@
// aux-build:re-export.rs
// edition:2018
extern crate re_export;
use re_export::cause_ice;
cause_ice!(); //~ ERROR `Variant` is only public within the crate, and cannot be re-exported outside
fn main() {}

View file

@ -0,0 +1,16 @@
error[E0364]: `Variant` is only public within the crate, and cannot be re-exported outside
--> $DIR/issue-79148.rs:8:1
|
LL | cause_ice!();
| ^^^^^^^^^^^^
|
note: consider marking `Variant` as `pub` in the imported module
--> $DIR/issue-79148.rs:8:1
|
LL | cause_ice!();
| ^^^^^^^^^^^^
= note: this error originates in the macro `cause_ice` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
For more information about this error, try `rustc --explain E0364`.

View file

@ -0,0 +1,29 @@
#![crate_type = "lib"]
#![feature(staged_api, rustc_attrs)]
#![stable(feature = "stable_feature", since = "1.0.0")]
#[stable(feature = "stable_feature", since = "1.0.0")]
pub trait JustTrait {
#[stable(feature = "stable_feature", since = "1.0.0")]
#[rustc_default_body_unstable(feature = "constant_default_body", issue = "none")]
const CONSTANT: usize = 0;
#[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")]
#[stable(feature = "stable_feature", since = "1.0.0")]
fn fun() {}
}
#[rustc_must_implement_one_of(eq, neq)]
#[stable(feature = "stable_feature", since = "1.0.0")]
pub trait Equal {
#[rustc_default_body_unstable(feature = "eq_default_body", issue = "none")]
#[stable(feature = "stable_feature", since = "1.0.0")]
fn eq(&self, other: &Self) -> bool {
!self.neq(other)
}
#[stable(feature = "stable_feature", since = "1.0.0")]
fn neq(&self, other: &Self) -> bool {
!self.eq(other)
}
}

View file

@ -0,0 +1,19 @@
// aux-build:default_body.rs
#![crate_type = "lib"]
extern crate default_body;
use default_body::{Equal, JustTrait};
struct Type;
impl JustTrait for Type {}
//~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046]
//~| ERROR not all trait items implemented, missing: `fun` [E0046]
impl Equal for Type {
//~^ ERROR not all trait items implemented, missing: `eq` [E0046]
fn neq(&self, other: &Self) -> bool {
false
}
}

View file

@ -0,0 +1,38 @@
error[E0046]: not all trait items implemented, missing: `CONSTANT`
--> $DIR/default-body-stability-err.rs:10:1
|
LL | impl JustTrait for Type {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: default implementation of `CONSTANT` is unstable
= note: use of unstable library feature 'constant_default_body'
= help: add `#![feature(constant_default_body)]` to the crate attributes to enable
error[E0046]: not all trait items implemented, missing: `fun`
--> $DIR/default-body-stability-err.rs:10:1
|
LL | impl JustTrait for Type {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: default implementation of `fun` is unstable
= note: use of unstable library feature 'fun_default_body'
= help: add `#![feature(fun_default_body)]` to the crate attributes to enable
error[E0046]: not all trait items implemented, missing: `eq`
--> $DIR/default-body-stability-err.rs:14:1
|
LL | / impl Equal for Type {
LL | |
LL | | fn neq(&self, other: &Self) -> bool {
LL | | false
LL | | }
LL | | }
| |_^
|
= note: default implementation of `eq` is unstable
= note: use of unstable library feature 'eq_default_body'
= help: add `#![feature(eq_default_body)]` to the crate attributes to enable
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0046`.

View file

@ -0,0 +1,18 @@
// check-pass
// aux-build:default_body.rs
#![crate_type = "lib"]
#![feature(fun_default_body, eq_default_body, constant_default_body)]
extern crate default_body;
use default_body::{Equal, JustTrait};
struct Type;
impl JustTrait for Type {}
impl Equal for Type {
fn neq(&self, other: &Self) -> bool {
false
}
}

View file

@ -0,0 +1,21 @@
// check-pass
// aux-build:default_body.rs
#![crate_type = "lib"]
extern crate default_body;
use default_body::{Equal, JustTrait};
struct Type;
impl JustTrait for Type {
const CONSTANT: usize = 1;
fn fun() {}
}
impl Equal for Type {
fn eq(&self, other: &Self) -> bool {
false
}
}

View file

@ -1,12 +0,0 @@
// Black and White have the same discriminator value ...
enum Color {
//~^ ERROR discriminant value `0` assigned more than once
Red = 0xff0000,
Green = 0x00ff00,
Blue = 0x0000ff,
Black = 0x000000,
White = 0x000000,
}
fn main() { }

View file

@ -1,14 +0,0 @@
error[E0081]: discriminant value `0` assigned more than once
--> $DIR/tag-variant-disr-dup.rs:3:1
|
LL | enum Color {
| ^^^^^^^^^^
...
LL | Black = 0x000000,
| -------- first assignment of `0`
LL | White = 0x000000,
| -------- second assignment of `0`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0081`.

View file

@ -4,13 +4,13 @@
use std::vec::IntoIter; use std::vec::IntoIter;
pub trait Foo: Iterator<Item=<Self as Foo>::Key> { pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
type Key; type Key;
} }
impl Foo for IntoIter<i32> { impl Foo for IntoIter<i32> {
type Key = u32; //~ ERROR type mismatch type Key = u32;
//~^ ERROR expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
} }
fn main() { fn main() {}
}

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::vec::IntoIter<i32> as Iterator>::Item == u32` error[E0271]: expected `std::vec::IntoIter<i32>` to be an iterator that yields `u32`, but it yields `i32`
--> $DIR/assoc-type-in-superbad.rs:12:16 --> $DIR/assoc-type-in-superbad.rs:12:16
| |
LL | type Key = u32; LL | type Key = u32;
@ -7,8 +7,8 @@ LL | type Key = u32;
note: required by a bound in `Foo` note: required by a bound in `Foo`
--> $DIR/assoc-type-in-superbad.rs:7:25 --> $DIR/assoc-type-in-superbad.rs:7:25
| |
LL | pub trait Foo: Iterator<Item=<Self as Foo>::Key> { LL | pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo` | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
error: aborting due to previous error error: aborting due to previous error

View file

@ -8,7 +8,7 @@ trait Foo {
impl Foo for () { impl Foo for () {
type Bar = std::vec::IntoIter<u32>; type Bar = std::vec::IntoIter<u32>;
//~^ ERROR type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X //~^ ERROR expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
} }
fn incoherent() { fn incoherent() {

View file

@ -1,4 +1,4 @@
error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as Iterator>::Item == X` error[E0271]: expected `std::vec::IntoIter<u32>` to be an iterator that yields `X`, but it yields `u32`
--> $DIR/issue-57961.rs:10:16 --> $DIR/issue-57961.rs:10:16
| |
LL | type X = impl Sized; LL | type X = impl Sized;

View file

@ -1,13 +1,11 @@
// edition:2018 // edition:2018
type AsyncFnPtr = Box< type AsyncFnPtr = Box<dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>>;
dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>,
>;
async fn test() {} async fn test() {}
#[allow(unused_must_use)] #[allow(unused_must_use)]
fn main() { fn main() {
Box::new(test) as AsyncFnPtr; Box::new(test) as AsyncFnPtr;
//~^ ERROR type mismatch //~^ ERROR expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
} }

View file

@ -1,11 +1,11 @@
error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>` error[E0271]: expected `fn() -> impl Future<Output = ()> {test}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
--> $DIR/issue-98604.rs:11:5 --> $DIR/issue-98604.rs:9:5
| |
LL | Box::new(test) as AsyncFnPtr; LL | Box::new(test) as AsyncFnPtr;
| ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type | ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
| |
note: while checking the return type of the `async fn` note: while checking the return type of the `async fn`
--> $DIR/issue-98604.rs:7:17 --> $DIR/issue-98604.rs:5:17
| |
LL | async fn test() {} LL | async fn test() {}
| ^ checked the `Output` of this `async fn`, found opaque type | ^ checked the `Output` of this `async fn`, found opaque type

View file

@ -1,8 +1,10 @@
fn hi() -> impl Sized { std::ptr::null::<u8>() } fn hi() -> impl Sized {
std::ptr::null::<u8>()
}
fn main() { fn main() {
let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi); let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
//~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>` //~^ ERROR expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
let boxed = b(); let boxed = b();
let null = *boxed; let null = *boxed;
println!("{null:?}"); println!("{null:?}");

View file

@ -1,7 +1,7 @@
error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>` error[E0271]: expected `fn() -> impl Sized {hi}` to be a fn item that returns `Box<u8>`, but it returns `impl Sized`
--> $DIR/issue-98608.rs:4:39 --> $DIR/issue-98608.rs:6:39
| |
LL | fn hi() -> impl Sized { std::ptr::null::<u8>() } LL | fn hi() -> impl Sized {
| ---------- the found opaque type | ---------- the found opaque type
... ...
LL | let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi); LL | let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);

View file

@ -2,9 +2,12 @@ error[E0615]: attempted to take value of method `read` on type `*mut Foo`
--> $DIR/issue-91210-ptr-method.rs:10:7 --> $DIR/issue-91210-ptr-method.rs:10:7
| |
LL | x.read = 4; LL | x.read = 4;
| - ^^^^ method, not a field | ^^^^ method, not a field
| | |
| help: to access the field, dereference first: `(*x)` help: to access the field, dereference first
|
LL | (*x).read = 4;
| ++ +
error: aborting due to previous error error: aborting due to previous error

View file

@ -19,7 +19,7 @@ Before submitting, please make sure that you're not running into one of these kn
Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3. Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
--> -->
**rust-analyzer version**: (eg. output of "Rust Analyzer: Show RA Version" command) **rust-analyzer version**: (eg. output of "rust-analyzer: Show RA Version" command, accessible in VSCode via <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>)
**rustc version**: (eg. output of `rustc -V`) **rustc version**: (eg. output of `rustc -V`)

View file

@ -18,6 +18,7 @@ env:
FETCH_DEPTH: 0 # pull in the tags for the version string FETCH_DEPTH: 0 # pull in the tags for the version string
MACOSX_DEPLOYMENT_TARGET: 10.15 MACOSX_DEPLOYMENT_TARGET: 10.15
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
jobs: jobs:
dist: dist:
@ -36,6 +37,9 @@ jobs:
- os: ubuntu-18.04 - os: ubuntu-18.04
target: aarch64-unknown-linux-gnu target: aarch64-unknown-linux-gnu
code-target: linux-arm64 code-target: linux-arm64
- os: ubuntu-18.04
target: arm-unknown-linux-gnueabihf
code-target: linux-armhf
- os: macos-11 - os: macos-11
target: x86_64-apple-darwin target: x86_64-apple-darwin
code-target: darwin-x64 code-target: darwin-x64
@ -67,13 +71,17 @@ jobs:
node-version: 14.x node-version: 14.x
- name: Update apt repositories - name: Update apt repositories
if: matrix.target == 'aarch64-unknown-linux-gnu' if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get update run: sudo apt-get update
- name: Install target toolchain - name: Install AArch64 target toolchain
if: matrix.target == 'aarch64-unknown-linux-gnu' if: matrix.target == 'aarch64-unknown-linux-gnu'
run: sudo apt-get install gcc-aarch64-linux-gnu run: sudo apt-get install gcc-aarch64-linux-gnu
- name: Install ARM target toolchain
if: matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get install gcc-arm-linux-gnueabihf
- name: Dist - name: Dist
run: cargo xtask dist --client-patch-version ${{ github.run_number }} run: cargo xtask dist --client-patch-version ${{ github.run_number }}
@ -204,6 +212,10 @@ jobs:
with: with:
name: dist-aarch64-unknown-linux-gnu name: dist-aarch64-unknown-linux-gnu
path: dist path: dist
- uses: actions/download-artifact@v1
with:
name: dist-arm-unknown-linux-gnueabihf
path: dist
- uses: actions/download-artifact@v1 - uses: actions/download-artifact@v1
with: with:
name: dist-x86_64-pc-windows-msvc name: dist-x86_64-pc-windows-msvc

View file

@ -43,7 +43,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
## License ## License
Rust analyzer is primarily distributed under the terms of both the MIT rust-analyzer is primarily distributed under the terms of both the MIT
license and the Apache License (Version 2.0). license and the Apache License (Version 2.0).
See LICENSE-APACHE and LICENSE-MIT for details. See LICENSE-APACHE and LICENSE-MIT for details.

View file

@ -57,6 +57,7 @@ pub struct FlycheckHandle {
// XXX: drop order is significant // XXX: drop order is significant
sender: Sender<Restart>, sender: Sender<Restart>,
_thread: jod_thread::JoinHandle, _thread: jod_thread::JoinHandle,
id: usize,
} }
impl FlycheckHandle { impl FlycheckHandle {
@ -72,18 +73,22 @@ impl FlycheckHandle {
.name("Flycheck".to_owned()) .name("Flycheck".to_owned())
.spawn(move || actor.run(receiver)) .spawn(move || actor.run(receiver))
.expect("failed to spawn thread"); .expect("failed to spawn thread");
FlycheckHandle { sender, _thread: thread } FlycheckHandle { id, sender, _thread: thread }
} }
/// Schedule a re-start of the cargo check worker. /// Schedule a re-start of the cargo check worker.
pub fn update(&self) { pub fn update(&self) {
self.sender.send(Restart).unwrap(); self.sender.send(Restart).unwrap();
} }
pub fn id(&self) -> usize {
self.id
}
} }
pub enum Message { pub enum Message {
/// Request adding a diagnostic with fixes included to a file /// Request adding a diagnostic with fixes included to a file
AddDiagnostic { workspace_root: AbsPathBuf, diagnostic: Diagnostic }, AddDiagnostic { id: usize, workspace_root: AbsPathBuf, diagnostic: Diagnostic },
/// Request check progress notification to client /// Request check progress notification to client
Progress { Progress {
@ -96,8 +101,9 @@ pub enum Message {
impl fmt::Debug for Message { impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Message::AddDiagnostic { workspace_root, diagnostic } => f Message::AddDiagnostic { id, workspace_root, diagnostic } => f
.debug_struct("AddDiagnostic") .debug_struct("AddDiagnostic")
.field("id", id)
.field("workspace_root", workspace_root) .field("workspace_root", workspace_root)
.field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code)) .field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
.finish(), .finish(),
@ -183,7 +189,7 @@ impl FlycheckActor {
} }
} }
Event::CheckEvent(None) => { Event::CheckEvent(None) => {
tracing::debug!("flycheck finished"); tracing::debug!(flycheck_id = self.id, "flycheck finished");
// Watcher finished // Watcher finished
let cargo_handle = self.cargo_handle.take().unwrap(); let cargo_handle = self.cargo_handle.take().unwrap();
@ -203,6 +209,7 @@ impl FlycheckActor {
CargoMessage::Diagnostic(msg) => { CargoMessage::Diagnostic(msg) => {
self.send(Message::AddDiagnostic { self.send(Message::AddDiagnostic {
id: self.id,
workspace_root: self.workspace_root.clone(), workspace_root: self.workspace_root.clone(),
diagnostic: msg, diagnostic: msg,
}); });

Some files were not shown because too many files have changed in this diff Show more