mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-19 11:12:43 +00:00
Merge branch 'rust-lang:master' into issue-98861-fix
This commit is contained in:
commit
0436067210
@ -4626,6 +4626,7 @@ dependencies = [
|
||||
"rustc_attr",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_graphviz",
|
||||
"rustc_hir",
|
||||
"rustc_hir_pretty",
|
||||
|
@ -417,6 +417,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
|| attr.has_name(sym::stable)
|
||||
|| attr.has_name(sym::rustc_const_unstable)
|
||||
|| attr.has_name(sym::rustc_const_stable)
|
||||
|| attr.has_name(sym::rustc_default_body_unstable)
|
||||
{
|
||||
struct_span_err!(
|
||||
self.sess,
|
||||
|
@ -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.
|
||||
#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||
#[derive(HashStable_Generic)]
|
||||
@ -214,7 +222,8 @@ pub fn find_stability(
|
||||
sess: &Session,
|
||||
attrs: &[Attribute],
|
||||
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)
|
||||
}
|
||||
|
||||
@ -222,7 +231,7 @@ fn find_stability_generic<'a, I>(
|
||||
sess: &Session,
|
||||
attrs_iter: I,
|
||||
item_sp: Span,
|
||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>)
|
||||
) -> (Option<(Stability, Span)>, Option<(ConstStability, Span)>, Option<(DefaultBodyStability, Span)>)
|
||||
where
|
||||
I: Iterator<Item = &'a Attribute>,
|
||||
{
|
||||
@ -230,6 +239,7 @@ where
|
||||
|
||||
let mut stab: Option<(Stability, Span)> = None;
|
||||
let mut const_stab: Option<(ConstStability, Span)> = None;
|
||||
let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
|
||||
let mut promotable = false;
|
||||
let mut allowed_through_unstable_modules = false;
|
||||
|
||||
@ -243,6 +253,7 @@ where
|
||||
sym::stable,
|
||||
sym::rustc_promotable,
|
||||
sym::rustc_allowed_through_unstable_modules,
|
||||
sym::rustc_default_body_unstable,
|
||||
]
|
||||
.iter()
|
||||
.any(|&s| attr.has_name(s))
|
||||
@ -280,7 +291,7 @@ where
|
||||
|
||||
let meta_name = meta.name_or_empty();
|
||||
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() {
|
||||
handle_errors(
|
||||
&sess.parse_sess,
|
||||
@ -295,6 +306,13 @@ where
|
||||
AttrError::MultipleStabilityLevels,
|
||||
);
|
||||
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;
|
||||
@ -405,11 +423,16 @@ where
|
||||
};
|
||||
if sym::unstable == meta_name {
|
||||
stab = Some((Stability { level, feature }, attr.span));
|
||||
} else {
|
||||
} else if sym::rustc_const_unstable == meta_name {
|
||||
const_stab = Some((
|
||||
ConstStability { level, feature, promotable: false },
|
||||
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, _, _) => {
|
||||
@ -542,7 +565,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
(stab, const_stab)
|
||||
(stab, const_stab, body_stab)
|
||||
}
|
||||
|
||||
pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
|
||||
|
@ -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.
|
||||
/// 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(
|
||||
&self,
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// The caller is responsible for calling the access hooks!
|
||||
///
|
||||
|
@ -772,7 +772,7 @@ impl SyntaxExtension {
|
||||
)
|
||||
})
|
||||
.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 {
|
||||
sess.parse_sess
|
||||
.span_diagnostic
|
||||
@ -784,6 +784,17 @@ impl SyntaxExtension {
|
||||
)
|
||||
.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 {
|
||||
kind,
|
||||
|
@ -499,6 +499,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
),
|
||||
ungated!(rustc_const_unstable, 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!(
|
||||
allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk,
|
||||
"allow_internal_unstable side-steps feature gating and stability checks",
|
||||
|
@ -207,6 +207,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
||||
def_ident_span => { table }
|
||||
lookup_stability => { table }
|
||||
lookup_const_stability => { table }
|
||||
lookup_default_body_stability => { table }
|
||||
lookup_deprecation_entry => { table }
|
||||
visibility => { table }
|
||||
unused_generic_params => { table }
|
||||
|
@ -1029,6 +1029,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
if should_encode_stability(def_kind) {
|
||||
self.encode_stability(def_id);
|
||||
self.encode_const_stability(def_id);
|
||||
self.encode_default_body_stability(def_id);
|
||||
self.encode_deprecation(def_id);
|
||||
}
|
||||
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) {
|
||||
debug!("EncodeContext::encode_deprecation({:?})", def_id);
|
||||
if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
|
||||
|
@ -343,6 +343,7 @@ define_tables! {
|
||||
def_ident_span: Table<DefIndex, LazyValue<Span>>,
|
||||
lookup_stability: Table<DefIndex, LazyValue<attr::Stability>>,
|
||||
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>>,
|
||||
// As an optimization, a missing entry indicates an empty `&[]`.
|
||||
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
|
||||
|
@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
|
||||
|
||||
use crate::ty::{self, DefIdTree, TyCtxt};
|
||||
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_errors::{Applicability, Diagnostic};
|
||||
use rustc_feature::GateIssue;
|
||||
@ -61,6 +61,7 @@ pub struct Index {
|
||||
/// are filled by the annotator.
|
||||
pub stab_map: FxHashMap<LocalDefId, Stability>,
|
||||
pub const_stab_map: FxHashMap<LocalDefId, ConstStability>,
|
||||
pub default_body_stab_map: FxHashMap<LocalDefId, DefaultBodyStability>,
|
||||
pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
|
||||
/// 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
|
||||
@ -86,6 +87,10 @@ impl Index {
|
||||
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> {
|
||||
self.depr_map.get(&def_id).cloned()
|
||||
}
|
||||
@ -416,6 +421,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
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);
|
||||
debug!(
|
||||
"stability: \
|
||||
@ -423,12 +434,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
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.
|
||||
if skip_stability_check_due_to_privacy(self, def_id) {
|
||||
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.
|
||||
///
|
||||
/// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
|
||||
|
@ -80,6 +80,8 @@ macro_rules! make_mir_visitor {
|
||||
self.super_body(body);
|
||||
}
|
||||
|
||||
extra_body_methods!($($mutability)?);
|
||||
|
||||
fn visit_basic_block_data(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
@ -287,63 +289,7 @@ macro_rules! make_mir_visitor {
|
||||
&mut self,
|
||||
body: &$($mutability)? Body<'tcx>,
|
||||
) {
|
||||
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 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);
|
||||
}
|
||||
super_body!(self, body, $($mutability, true)?);
|
||||
}
|
||||
|
||||
fn super_basic_block_data(&mut self,
|
||||
@ -982,12 +928,7 @@ macro_rules! make_mir_visitor {
|
||||
body: &$($mutability)? Body<'tcx>,
|
||||
location: Location
|
||||
) {
|
||||
#[allow(unused_macro_rules)]
|
||||
macro_rules! basic_blocks {
|
||||
(mut) => (body.basic_blocks_mut());
|
||||
() => (body.basic_blocks());
|
||||
}
|
||||
let basic_block = & $($mutability)? basic_blocks!($($mutability)?)[location.block];
|
||||
let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
|
||||
if basic_block.statements.len() == location.statement_index {
|
||||
if let Some(ref $($mutability)? terminator) = basic_block.terminator {
|
||||
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 {
|
||||
(mut) => {
|
||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
|
||||
|
@ -1094,6 +1094,11 @@ rustc_queries! {
|
||||
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 {
|
||||
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(
|
||||
goal: CanonicalTyGoal<'tcx>
|
||||
) -> MethodAutoderefStepsResult<'tcx> {
|
||||
|
@ -64,6 +64,7 @@ trivially_parameterized_over_tcx! {
|
||||
rustc_ast::Attribute,
|
||||
rustc_ast::MacArgs,
|
||||
rustc_attr::ConstStability,
|
||||
rustc_attr::DefaultBodyStability,
|
||||
rustc_attr::Deprecation,
|
||||
rustc_attr::Stability,
|
||||
rustc_hir::Constness,
|
||||
|
@ -849,22 +849,22 @@ fn non_exhaustive_match<'p, 'tcx>(
|
||||
));
|
||||
}
|
||||
[.., 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(..))
|
||||
&& last.span.eq_ctxt(last.body.span)
|
||||
{
|
||||
""
|
||||
} else {
|
||||
","
|
||||
};
|
||||
let comma = if matches!(last.body.kind, hir::ExprKind::Block(..))
|
||||
&& last.span.eq_ctxt(last.body.span)
|
||||
{
|
||||
""
|
||||
} 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((
|
||||
last.span.shrink_to_hi(),
|
||||
format!(
|
||||
"{}{}{} => todo!()",
|
||||
comma,
|
||||
snippet.strip_prefix(',').unwrap_or(&snippet),
|
||||
pattern
|
||||
),
|
||||
format!("{}{}{} => todo!()", comma, spacing, pattern),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ pub struct DeleteNonCodegenStatements<'tcx> {
|
||||
impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let mut delete = DeleteNonCodegenStatements { tcx };
|
||||
delete.visit_body(body);
|
||||
delete.visit_body_preserves_cfg(body);
|
||||
body.user_type_annotations.raw.clear();
|
||||
|
||||
for decl in &mut body.local_decls {
|
||||
|
@ -951,7 +951,7 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, '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);
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
let patch = MirPatch::new(body);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
|
||||
ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
|
||||
|
||||
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;
|
||||
for statement in statements {
|
||||
|
@ -53,10 +53,10 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
|
||||
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.
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ impl<'tcx> MirPass<'tcx> for RevealAll {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,7 +412,7 @@ pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
|
||||
if map.iter().any(Option::is_none) {
|
||||
// Update references to all vars and tmps now
|
||||
let mut updater = LocalUpdater { map, tcx };
|
||||
updater.visit_body(body);
|
||||
updater.visit_body_preserves_cfg(body);
|
||||
|
||||
body.local_decls.shrink_to_fit();
|
||||
}
|
||||
@ -548,7 +548,7 @@ fn remove_unused_definitions(used_locals: &mut UsedLocals, body: &mut Body<'_>)
|
||||
while modified {
|
||||
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.
|
||||
data.statements.retain(|statement| {
|
||||
let keep = match &statement.kind {
|
||||
|
@ -29,11 +29,16 @@ impl<'tcx> LibFeatureCollector<'tcx> {
|
||||
}
|
||||
|
||||
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
|
||||
let stab_attrs =
|
||||
[sym::stable, sym::unstable, sym::rustc_const_stable, sym::rustc_const_unstable];
|
||||
let stab_attrs = [
|
||||
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(…)],
|
||||
// #[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)) {
|
||||
let meta_kind = attr.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
|
||||
// don't emit additional, irrelevant errors for malformed
|
||||
// attributes.
|
||||
let is_unstable =
|
||||
matches!(*stab_attr, sym::unstable | sym::rustc_const_unstable);
|
||||
let is_unstable = matches!(
|
||||
*stab_attr,
|
||||
sym::unstable
|
||||
| sym::rustc_const_unstable
|
||||
| sym::rustc_default_body_unstable
|
||||
);
|
||||
if since.is_some() || is_unstable {
|
||||
return Some((feature, since, attr.span));
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
//! Checks validity of naked functions.
|
||||
|
||||
use rustc_ast::{Attribute, InlineAsmOptions};
|
||||
use rustc_ast::InlineAsmOptions;
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::intravisit::{FnKind, Visitor};
|
||||
use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
|
||||
@ -13,71 +14,58 @@ use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
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) {
|
||||
*providers = Providers { check_mod_naked_functions, ..*providers };
|
||||
}
|
||||
|
||||
struct CheckNakedFunctions<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
|
||||
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;
|
||||
}
|
||||
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
let naked = attrs.iter().any(|attr| attr.has_name(sym::naked));
|
||||
if naked {
|
||||
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 naked = tcx.has_attr(def_id.to_def_id(), sym::naked);
|
||||
if !naked {
|
||||
continue;
|
||||
}
|
||||
|
||||
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.
|
||||
fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
|
||||
for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
|
||||
fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
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();
|
||||
});
|
||||
}
|
||||
@ -141,7 +129,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
|
||||
}
|
||||
|
||||
/// 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() };
|
||||
this.visit_body(body);
|
||||
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 {
|
||||
let mut diag = struct_span_err!(
|
||||
tcx.sess,
|
||||
fn_span,
|
||||
tcx.def_span(def_id),
|
||||
E0787,
|
||||
"naked functions must contain a single asm block"
|
||||
);
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! A pass that annotates every item and method with its stability level,
|
||||
//! propagating default levels lexically from parent to children ast nodes.
|
||||
|
||||
use attr::StabilityLevel;
|
||||
use rustc_attr::{self as attr, ConstStability, Stability, Unstable, UnstableReason};
|
||||
use rustc_attr::{
|
||||
self as attr, ConstStability, Stability, StabilityLevel, Unstable, UnstableReason,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{struct_span_err, Applicability};
|
||||
use rustc_hir as hir;
|
||||
@ -161,7 +162,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
|
||||
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 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)| {
|
||||
// Error if prohibited, or can't inherit anything from a container.
|
||||
if kind == AnnotationKind::Prohibited
|
||||
@ -613,6 +621,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
||||
let mut index = Index {
|
||||
stab_map: Default::default(),
|
||||
const_stab_map: Default::default(),
|
||||
default_body_stab_map: Default::default(),
|
||||
depr_map: Default::default(),
|
||||
implications: Default::default(),
|
||||
};
|
||||
@ -673,6 +682,9 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||
stability_implications: |tcx, _| tcx.stability().implications.clone(),
|
||||
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_default_body_stability: |tcx, id| {
|
||||
tcx.stability().local_default_body_stability(id.expect_local())
|
||||
},
|
||||
lookup_deprecation_entry: |tcx, id| {
|
||||
tcx.stability().local_deprecation_entry(id.expect_local())
|
||||
},
|
||||
@ -723,7 +735,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
||||
let features = self.tcx.features();
|
||||
if features.staged_api {
|
||||
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
|
||||
// error if all involved types and traits are stable, because
|
||||
|
@ -2544,12 +2544,15 @@ fn show_candidates(
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
if let [first, .., last] = &path[..] {
|
||||
err.span_suggestion_verbose(
|
||||
first.ident.span.until(last.ident.span),
|
||||
&format!("if you import `{}`, refer to it directly", last.ident),
|
||||
"",
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
let sp = first.ident.span.until(last.ident.span);
|
||||
if sp.can_be_used_for_suggestions() {
|
||||
err.span_suggestion_verbose(
|
||||
sp,
|
||||
&format!("if you import `{}`, refer to it directly", last.ident),
|
||||
"",
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
msg.push(':');
|
||||
|
@ -1218,6 +1218,7 @@ symbols! {
|
||||
rustc_conversion_suggestion,
|
||||
rustc_deallocator,
|
||||
rustc_def_path,
|
||||
rustc_default_body_unstable,
|
||||
rustc_diagnostic_item,
|
||||
rustc_diagnostic_macros,
|
||||
rustc_dirty,
|
||||
|
@ -1315,6 +1315,13 @@ trait InferCtxtPrivExt<'hir, '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(
|
||||
&self,
|
||||
a: Ty<'tcx>,
|
||||
@ -1542,23 +1549,19 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
normalized_ty,
|
||||
data.term,
|
||||
) {
|
||||
values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
|
||||
is_normalized_ty_expected,
|
||||
normalized_ty,
|
||||
data.term,
|
||||
)));
|
||||
values = Some((data, is_normalized_ty_expected, normalized_ty, data.term));
|
||||
err_buf = error;
|
||||
err = &err_buf;
|
||||
}
|
||||
}
|
||||
|
||||
let mut diag = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
obligation.cause.span,
|
||||
E0271,
|
||||
"type mismatch resolving `{}`",
|
||||
predicate
|
||||
);
|
||||
let msg = values
|
||||
.and_then(|(predicate, _, normalized_ty, expected_ty)| {
|
||||
self.maybe_detailed_projection_msg(predicate, normalized_ty, expected_ty)
|
||||
})
|
||||
.unwrap_or_else(|| format!("type mismatch resolving `{}`", predicate));
|
||||
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
|
||||
|
||||
let secondary_span = match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Projection(proj) => self
|
||||
.tcx
|
||||
@ -1596,7 +1599,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||
&mut diag,
|
||||
&obligation.cause,
|
||||
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,
|
||||
true,
|
||||
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(
|
||||
&self,
|
||||
mut a: Ty<'tcx>,
|
||||
|
@ -34,7 +34,10 @@ use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
|
||||
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 smallvec::SmallVec;
|
||||
|
||||
@ -503,6 +506,77 @@ fn subst_and_check_impossible_predicates<'tcx>(
|
||||
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(¶m, 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(¶m, 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)]
|
||||
enum VtblSegment<'tcx> {
|
||||
MetadataDSA,
|
||||
@ -883,6 +957,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
||||
vtable_entries,
|
||||
vtable_trait_upcasting_coercion_new_vptr_slot,
|
||||
subst_and_check_impossible_predicates,
|
||||
is_impossible_method,
|
||||
try_unify_abstract_consts: |tcx, param_env_and| {
|
||||
let (param_env, (a, b)) = param_env_and.into_parts();
|
||||
const_evaluatable::try_unify_abstract_consts(tcx, (a, b), param_env)
|
||||
|
@ -30,3 +30,4 @@ rustc_ty_utils = { path = "../rustc_ty_utils" }
|
||||
rustc_lint = { path = "../rustc_lint" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
|
@ -18,6 +18,7 @@ use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
|
||||
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::subst::GenericArgKind;
|
||||
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_ty_utils::representability::{self, Representability};
|
||||
|
||||
use std::iter;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
if let Some(required_items) = &must_implement_one_of {
|
||||
// true if this item is specifically implemented in this impl
|
||||
let is_implemented_here = ancestors
|
||||
.leaf_def(tcx, trait_item_id)
|
||||
.map_or(false, |node_item| !node_item.defining_node.is_from_trait());
|
||||
// true if this item is specifically implemented in this impl
|
||||
let is_implemented_here = ancestors
|
||||
.leaf_def(tcx, trait_item_id)
|
||||
.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 {
|
||||
let trait_item = tcx.associated_item(trait_item_id);
|
||||
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());
|
||||
// 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;
|
||||
}
|
||||
detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
|
||||
|
||||
check_representable(tcx, sp, def_id);
|
||||
check_transparent(tcx, sp, def);
|
||||
}
|
||||
|
||||
/// In the case that a discriminant is both a duplicate and an overflowing literal,
|
||||
/// we insert both the assigned discriminant and the literal it overflowed from into the formatted
|
||||
/// output. Otherwise we format the discriminant normally.
|
||||
fn format_discriminant_overflow<'tcx>(
|
||||
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
|
||||
fn detect_discriminant_duplicate<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
variant: &hir::Variant<'_>,
|
||||
dis: Discr<'tcx>,
|
||||
) -> String {
|
||||
if let Some(expr) = &variant.disr_expr {
|
||||
let body = &tcx.hir().body(expr.body).value;
|
||||
if let hir::ExprKind::Lit(lit) = &body.kind
|
||||
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
|
||||
&& dis.val != *lit_value
|
||||
{
|
||||
return format!("`{dis}` (overflowed from `{lit_value}`)");
|
||||
}
|
||||
}
|
||||
mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
|
||||
vs: &'tcx [hir::Variant<'tcx>],
|
||||
self_span: Span,
|
||||
) {
|
||||
// Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
|
||||
// Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
|
||||
let report = |dis: Discr<'tcx>,
|
||||
idx: usize,
|
||||
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| {
|
||||
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>(
|
||||
|
@ -1589,11 +1589,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||
) {
|
||||
let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
|
||||
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 {
|
||||
span.push_span_label(
|
||||
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(
|
||||
|
@ -50,7 +50,6 @@ use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::lev_distance::find_best_match_for_name;
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{BytePos, Pos};
|
||||
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||
@ -2398,37 +2397,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
expr,
|
||||
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 {
|
||||
let mut found = false;
|
||||
|
||||
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.help("methods are immutable and cannot be assigned to");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
|
@ -112,7 +112,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::{HirIdMap, ImplicitSelfKind, Node};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||
@ -122,13 +121,14 @@ use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
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::spec::abi::Abi;
|
||||
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::suggestions::ReturnsVisitor;
|
||||
use std::cell::RefCell;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use crate::require_c_abi_if_c_variadic;
|
||||
use crate::util::common::indenter;
|
||||
@ -662,6 +662,37 @@ fn missing_items_must_implement_one_of_err(
|
||||
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.
|
||||
fn bounds_from_generic_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -318,19 +318,11 @@ impl Duration {
|
||||
/// assert_eq!(duration.as_secs(), 5);
|
||||
/// ```
|
||||
///
|
||||
/// To determine the total number of seconds represented by the `Duration`,
|
||||
/// use `as_secs` in combination with [`subsec_nanos`]:
|
||||
///
|
||||
/// ```
|
||||
/// 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);
|
||||
/// ```
|
||||
/// To determine the total number of seconds represented by the `Duration`
|
||||
/// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`]
|
||||
///
|
||||
/// [`as_secs_f32`]: Duration::as_secs_f64
|
||||
/// [`as_secs_f64`]: Duration::as_secs_f32
|
||||
/// [`subsec_nanos`]: Duration::subsec_nanos
|
||||
#[stable(feature = "duration", since = "1.3.0")]
|
||||
#[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
|
||||
|
@ -628,6 +628,10 @@ impl Step for Miri {
|
||||
cargo.env("MIRI_HOST_SYSROOT", sysroot);
|
||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
||||
cargo.env("MIRI", miri);
|
||||
// propagate --bless
|
||||
if builder.config.cmd.bless() {
|
||||
cargo.env("MIRI_BLESS", "Gesundheit");
|
||||
}
|
||||
|
||||
cargo.arg("--").args(builder.config.cmd.test_args());
|
||||
|
||||
|
@ -88,8 +88,8 @@ def check_type(ty):
|
||||
for bound in binding["binding"]["constraint"]:
|
||||
check_generic_bound(bound)
|
||||
elif "parenthesized" in args:
|
||||
for ty in args["parenthesized"]["inputs"]:
|
||||
check_type(ty)
|
||||
for input_ty in args["parenthesized"]["inputs"]:
|
||||
check_type(input_ty)
|
||||
if args["parenthesized"]["output"]:
|
||||
check_type(args["parenthesized"]["output"])
|
||||
if not valid_id(ty["inner"]["id"]):
|
||||
|
@ -348,15 +348,13 @@ where
|
||||
fn make_final_bounds(
|
||||
&self,
|
||||
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>>,
|
||||
) -> Vec<WherePredicate> {
|
||||
ty_to_bounds
|
||||
.into_iter()
|
||||
.flat_map(|(ty, mut bounds)| {
|
||||
if let Some(data) = ty_to_fn.get(&ty) {
|
||||
let (poly_trait, output) =
|
||||
(data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
|
||||
if let Some((ref poly_trait, ref output)) = ty_to_fn.get(&ty) {
|
||||
let mut new_path = poly_trait.trait_.clone();
|
||||
let last_segment = new_path.segments.pop().expect("segments were empty");
|
||||
|
||||
@ -374,8 +372,9 @@ where
|
||||
GenericArgs::Parenthesized { inputs, output } => (inputs, output),
|
||||
};
|
||||
|
||||
let output = output.as_ref().cloned().map(Box::new);
|
||||
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 };
|
||||
@ -385,7 +384,10 @@ where
|
||||
.push(PathSegment { name: last_segment.name, args: new_params });
|
||||
|
||||
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,
|
||||
));
|
||||
}
|
||||
@ -471,10 +473,10 @@ where
|
||||
let mut lifetime_to_bounds: FxHashMap<_, FxHashSet<_>> = 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 {
|
||||
let (orig_p, p) = (p, p.clean(self.cx));
|
||||
let (orig_p, p) = (p, clean_predicate(p, self.cx));
|
||||
if p.is_none() {
|
||||
continue;
|
||||
}
|
||||
@ -535,8 +537,8 @@ where
|
||||
if is_fn {
|
||||
ty_to_fn
|
||||
.entry(ty.clone())
|
||||
.and_modify(|e| *e = (Some(poly_trait.clone()), e.1.clone()))
|
||||
.or_insert(((Some(poly_trait.clone())), None));
|
||||
.and_modify(|e| *e = (poly_trait.clone(), e.1.clone()))
|
||||
.or_insert(((poly_trait.clone()), None));
|
||||
|
||||
ty_to_bounds.entry(ty.clone()).or_default();
|
||||
} else {
|
||||
@ -559,7 +561,13 @@ where
|
||||
.and_modify(|e| {
|
||||
*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;
|
||||
}
|
||||
|
||||
|
@ -145,6 +145,7 @@ pub(crate) fn try_inline_glob(
|
||||
cx: &mut DocContext<'_>,
|
||||
res: Res,
|
||||
visited: &mut FxHashSet<DefId>,
|
||||
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
|
||||
) -> Option<Vec<clean::Item>> {
|
||||
let did = res.opt_def_id()?;
|
||||
if did.is_local() {
|
||||
@ -153,8 +154,17 @@ pub(crate) fn try_inline_glob(
|
||||
|
||||
match res {
|
||||
Res::Def(DefKind::Mod, did) => {
|
||||
let m = build_module(cx, did, visited);
|
||||
Some(m.items)
|
||||
let mut items = build_module_items(cx, did, visited, inlined_names);
|
||||
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
|
||||
_ => None,
|
||||
@ -517,6 +527,18 @@ fn build_module(
|
||||
did: DefId,
|
||||
visited: &mut FxHashSet<DefId>,
|
||||
) -> 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();
|
||||
|
||||
// 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() {
|
||||
let res = item.res.expect_non_local();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -563,8 +591,7 @@ fn build_module(
|
||||
}
|
||||
}
|
||||
|
||||
let span = clean::Span::new(cx.tcx.def_span(did));
|
||||
clean::Module { items, span }
|
||||
items
|
||||
}
|
||||
|
||||
pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
|
||||
|
@ -71,7 +71,7 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
|
||||
// priority to the not-imported one, so we should, too.
|
||||
items.extend(self.items.iter().flat_map(|(item, renamed)| {
|
||||
// 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();
|
||||
}
|
||||
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)| {
|
||||
// Now we actually lower the imports, skipping everything else.
|
||||
if !matches!(item.kind, hir::ItemKind::Use(..)) {
|
||||
return Vec::new();
|
||||
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
|
||||
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
|
||||
@ -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(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
|
||||
if !self.in_where_clause() {
|
||||
return None;
|
||||
}
|
||||
Some(match *self {
|
||||
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(),
|
||||
},
|
||||
})
|
||||
fn clean_where_predicate<'tcx>(
|
||||
predicate: &hir::WherePredicate<'tcx>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> Option<WherePredicate> {
|
||||
if !predicate.in_where_clause() {
|
||||
return None;
|
||||
}
|
||||
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> {
|
||||
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
|
||||
let bound_predicate = self.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Trait(pred) => {
|
||||
clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
|
||||
}
|
||||
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"),
|
||||
pub(crate) fn clean_predicate<'tcx>(
|
||||
predicate: ty::Predicate<'tcx>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> Option<WherePredicate> {
|
||||
let bound_predicate = predicate.kind();
|
||||
match bound_predicate.skip_binder() {
|
||||
ty::PredicateKind::Trait(pred) => {
|
||||
clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
|
||||
}
|
||||
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 {
|
||||
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
|
||||
@ -702,7 +701,7 @@ fn clean_ty_generics<'tcx>(
|
||||
|
||||
if let Some(param_idx) = param_idx {
|
||||
if let Some(b) = impl_trait.get_mut(¶m_idx.into()) {
|
||||
let p: WherePredicate = p.clean(cx)?;
|
||||
let p: WherePredicate = clean_predicate(*p, cx)?;
|
||||
|
||||
b.extend(
|
||||
p.get_bounds()
|
||||
@ -759,7 +758,7 @@ fn clean_ty_generics<'tcx>(
|
||||
// Now that `cx.impl_trait_bounds` is populated, we can process
|
||||
// remaining predicates which could contain `impl Trait`.
|
||||
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
|
||||
// ?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);
|
||||
}
|
||||
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"),
|
||||
};
|
||||
@ -2083,6 +2082,7 @@ fn clean_use_statement<'tcx>(
|
||||
path: &hir::Path<'tcx>,
|
||||
kind: hir::UseKind,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
|
||||
) -> Vec<Item> {
|
||||
// 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
|
||||
@ -2148,7 +2148,8 @@ fn clean_use_statement<'tcx>(
|
||||
let inner = if kind == hir::UseKind::Glob {
|
||||
if !denied {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1550,6 +1550,15 @@ fn render_impl(
|
||||
rendering_params: ImplRenderingParameters,
|
||||
) {
|
||||
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;
|
||||
if i.items.iter().any(|m| m.name == n) {
|
||||
continue;
|
||||
|
@ -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 {
|
||||
#[rustfmt::skip]
|
||||
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::*;
|
||||
match args {
|
||||
AngleBracketed { args, bindings } => GenericArgs::AngleBracketed {
|
||||
args: args.into_vec().into_iter().map(|a| a.into_tcx(tcx)).collect(),
|
||||
bindings: bindings.into_iter().map(|a| a.into_tcx(tcx)).collect(),
|
||||
args: args.into_vec().into_tcx(tcx),
|
||||
bindings: bindings.into_tcx(tcx),
|
||||
},
|
||||
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)),
|
||||
},
|
||||
}
|
||||
@ -145,7 +155,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
|
||||
fn from_tcx(arg: clean::GenericArg, tcx: TyCtxt<'_>) -> Self {
|
||||
use clean::GenericArg::*;
|
||||
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)),
|
||||
Const(box c) => GenericArg::Const(c.into_tcx(tcx)),
|
||||
Infer => GenericArg::Infer,
|
||||
@ -177,9 +187,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
|
||||
use clean::TypeBindingKind::*;
|
||||
match kind {
|
||||
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
|
||||
Constraint { bounds } => {
|
||||
TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
|
||||
}
|
||||
Constraint { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,7 +252,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
||||
TraitAliasItem(t) => ItemEnum::TraitAlias(t.into_tcx(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)),
|
||||
ImplItem(i) => ItemEnum::Impl(i.into_tcx(tcx)),
|
||||
ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
|
||||
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
|
||||
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
|
||||
ForeignTypeItem => ItemEnum::ForeignType,
|
||||
@ -260,12 +268,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
||||
}
|
||||
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
|
||||
generics: (*g).into_tcx(tcx),
|
||||
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
|
||||
bounds: b.into_tcx(tcx),
|
||||
default: None,
|
||||
},
|
||||
AssocTypeItem(t, b) => ItemEnum::AssocType {
|
||||
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)),
|
||||
},
|
||||
// `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 {
|
||||
fn from_tcx(generics: clean::Generics, tcx: TyCtxt<'_>) -> Self {
|
||||
Generics {
|
||||
params: generics.params.into_iter().map(|x| x.into_tcx(tcx)).collect(),
|
||||
where_predicates: generics
|
||||
.where_predicates
|
||||
.into_iter()
|
||||
.map(|x| x.into_tcx(tcx))
|
||||
.collect(),
|
||||
params: generics.params.into_tcx(tcx),
|
||||
where_predicates: generics.where_predicates.into_tcx(tcx),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,10 +382,10 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
|
||||
use clean::GenericParamDefKind::*;
|
||||
match kind {
|
||||
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 {
|
||||
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
|
||||
bounds: bounds.into_tcx(tcx),
|
||||
default: default.map(|x| (*x).into_tcx(tcx)),
|
||||
synthetic,
|
||||
},
|
||||
@ -395,7 +403,7 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
|
||||
match predicate {
|
||||
BoundPredicate { ty, bounds, bound_params } => WherePredicate::BoundPredicate {
|
||||
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
|
||||
.into_iter()
|
||||
.map(|x| GenericParamDef {
|
||||
@ -405,8 +413,8 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
|
||||
.collect(),
|
||||
},
|
||||
RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate {
|
||||
lifetime: lifetime.0.to_string(),
|
||||
bounds: bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
|
||||
lifetime: convert_lifetime(lifetime),
|
||||
bounds: bounds.into_tcx(tcx),
|
||||
},
|
||||
EqPredicate { lhs, rhs } => {
|
||||
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);
|
||||
GenericBound::TraitBound {
|
||||
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),
|
||||
}
|
||||
}
|
||||
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 {
|
||||
fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
|
||||
use clean::Type::{
|
||||
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive,
|
||||
QPath, RawPointer, Slice, Tuple,
|
||||
Array, BareFunction, BorrowedRef, Generic, ImplTrait, Infer, Primitive, QPath,
|
||||
RawPointer, Slice, Tuple,
|
||||
};
|
||||
|
||||
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))),
|
||||
param_names: Vec::new(),
|
||||
},
|
||||
DynTrait(mut bounds, lt) => {
|
||||
let first_trait = bounds.remove(0).trait_;
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
clean::Type::DynTrait(bounds, lt) => Type::DynTrait(DynTrait {
|
||||
lifetime: lt.map(convert_lifetime),
|
||||
traits: bounds.into_tcx(tcx),
|
||||
}),
|
||||
Generic(s) => Type::Generic(s.to_string()),
|
||||
Primitive(p) => Type::Primitive(p.as_sym().to_string()),
|
||||
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))),
|
||||
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,
|
||||
RawPointer(mutability, type_) => Type::RawPointer {
|
||||
mutable: mutability == ast::Mutability::Mut,
|
||||
type_: Box::new((*type_).into_tcx(tcx)),
|
||||
},
|
||||
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
|
||||
lifetime: lifetime.map(|l| l.0.to_string()),
|
||||
lifetime: lifetime.map(convert_lifetime),
|
||||
mutable: mutability == ast::Mutability::Mut,
|
||||
type_: Box::new((*type_).into_tcx(tcx)),
|
||||
},
|
||||
@ -528,7 +520,7 @@ impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
|
||||
async_: false,
|
||||
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),
|
||||
}
|
||||
}
|
||||
@ -562,16 +554,28 @@ impl FromWithTcx<clean::Trait> for Trait {
|
||||
is_unsafe,
|
||||
items: ids(items, 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWithTcx<Box<clean::Impl>> for Impl {
|
||||
fn from_tcx(impl_: Box<clean::Impl>, tcx: TyCtxt<'_>) -> Self {
|
||||
impl FromWithTcx<clean::PolyTrait> for PolyTrait {
|
||||
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 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?
|
||||
let trait_ = trait_.map(|path| clean::Type::Path { path }.into_tcx(tcx));
|
||||
// FIXME: use something like ImplKind in JSON?
|
||||
@ -730,10 +734,7 @@ impl FromWithTcx<Box<clean::Typedef>> for Typedef {
|
||||
|
||||
impl FromWithTcx<clean::OpaqueTy> for OpaqueTy {
|
||||
fn from_tcx(opaque: clean::OpaqueTy, tcx: TyCtxt<'_>) -> Self {
|
||||
OpaqueTy {
|
||||
bounds: opaque.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
|
||||
generics: opaque.generics.into_tcx(tcx),
|
||||
}
|
||||
OpaqueTy { bounds: opaque.bounds.into_tcx(tcx), generics: opaque.generics.into_tcx(tcx) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,10 +750,7 @@ impl FromWithTcx<clean::Static> for Static {
|
||||
|
||||
impl FromWithTcx<clean::TraitAlias> for TraitAlias {
|
||||
fn from_tcx(alias: clean::TraitAlias, tcx: TyCtxt<'_>) -> Self {
|
||||
TraitAlias {
|
||||
generics: alias.generics.into_tcx(tcx),
|
||||
params: alias.bounds.into_iter().map(|x| x.into_tcx(tcx)).collect(),
|
||||
}
|
||||
TraitAlias { generics: alias.generics.into_tcx(tcx), params: alias.bounds.into_tcx(tcx) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use std::path::PathBuf;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 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
|
||||
/// 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)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum GenericArgs {
|
||||
@ -395,7 +424,7 @@ pub enum WherePredicate {
|
||||
type_: Type,
|
||||
bounds: Vec<GenericBound>,
|
||||
/// Used for Higher-Rank Trait Bounds (HRTBs)
|
||||
/// ```plain
|
||||
/// ```text
|
||||
/// where for<'a> &'a T: Iterator,"
|
||||
/// ^^^^^^^
|
||||
/// |
|
||||
@ -420,7 +449,7 @@ pub enum GenericBound {
|
||||
#[serde(rename = "trait")]
|
||||
trait_: Type,
|
||||
/// Used for Higher-Rank Trait Bounds (HRTBs)
|
||||
/// ```plain
|
||||
/// ```text
|
||||
/// where F: for<'a, 'b> Fn(&'a u8, &'b u8)
|
||||
/// ^^^^^^^^^^^
|
||||
/// |
|
||||
@ -458,6 +487,7 @@ pub enum Type {
|
||||
args: Option<Box<GenericArgs>>,
|
||||
param_names: Vec<GenericBound>,
|
||||
},
|
||||
DynTrait(DynTrait),
|
||||
/// Parameterized types
|
||||
Generic(String),
|
||||
/// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples
|
||||
@ -505,7 +535,7 @@ pub enum Type {
|
||||
pub struct FunctionPointer {
|
||||
pub decl: FnDecl,
|
||||
/// Used for Higher-Rank Trait Bounds (HRTBs)
|
||||
/// ```plain
|
||||
/// ```text
|
||||
/// for<'c> fn(val: &'c i32) -> i32
|
||||
/// ^^^^^^^
|
||||
/// |
|
||||
|
@ -1,8 +1,13 @@
|
||||
// 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"
|
||||
// @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')].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.args.angle_bracketed.bindings" []
|
||||
// @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" \"resolved_path\"
|
||||
// @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.param_names[*]" 3
|
||||
// @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.param_names[1].trait_bound.trait.inner.name" \"Sync\"
|
||||
// @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.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
|
||||
// @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.inner.lifetime" \"\'static\"
|
||||
// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.traits[*]" 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.traits[1].generic_params" []
|
||||
// @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.traits[0].trait.inner.name" '"Fn"'
|
||||
// @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>;
|
||||
|
||||
// @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>;
|
||||
|
26
src/test/rustdoc-json/type/hrtb.rs
Normal file
26
src/test/rustdoc-json/type/hrtb.rs
Normal 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);
|
||||
}
|
13
src/test/rustdoc/auxiliary/issue-100204-aux.rs
Normal file
13
src/test/rustdoc/auxiliary/issue-100204-aux.rs
Normal 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
|
||||
}
|
||||
}
|
21
src/test/rustdoc/fn-bound.rs
Normal file
21
src/test/rustdoc/fn-bound.rs
Normal 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!()
|
||||
}
|
||||
}
|
20
src/test/rustdoc/impossible-default.rs
Normal file
20
src/test/rustdoc/impossible-default.rs
Normal 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 {}
|
@ -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::*;
|
@ -57,13 +57,11 @@ LL | a + 1
|
||||
error[E0787]: naked functions must contain a single asm block
|
||||
--> $DIR/naked-functions.rs:33:1
|
||||
|
|
||||
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
|
||||
LL | |
|
||||
LL | | a + 1
|
||||
| | ----- non-asm is unsupported in naked functions
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | a + 1
|
||||
| ----- non-asm is unsupported in naked functions
|
||||
|
||||
error: referencing function parameters is not allowed in naked functions
|
||||
--> $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
|
||||
--> $DIR/naked-functions.rs:48:1
|
||||
|
|
||||
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
|
||||
LL | |
|
||||
LL | | (|| a + 1)()
|
||||
| | ------------ non-asm is unsupported in naked functions
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | (|| a + 1)()
|
||||
| ------------ non-asm is unsupported in naked functions
|
||||
|
||||
error[E0787]: only `const` and `sym` operands are supported in naked functions
|
||||
--> $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
|
||||
--> $DIR/naked-functions.rs:54:1
|
||||
|
|
||||
LL | / pub unsafe extern "C" fn unsupported_operands() {
|
||||
LL | |
|
||||
LL | | let mut a = 0usize;
|
||||
| | ------------------- non-asm is unsupported in naked functions
|
||||
LL | | let mut b = 0usize;
|
||||
| | ------------------- non-asm is unsupported in naked functions
|
||||
LL | | let mut c = 0usize;
|
||||
| | ------------------- non-asm is unsupported in naked functions
|
||||
LL | | let mut d = 0usize;
|
||||
| | ------------------- non-asm is unsupported in naked functions
|
||||
LL | | let mut e = 0usize;
|
||||
| | ------------------- non-asm is unsupported in naked functions
|
||||
... |
|
||||
LL | | );
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | pub unsafe extern "C" fn unsupported_operands() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | let mut a = 0usize;
|
||||
| ------------------- non-asm is unsupported in naked functions
|
||||
LL | let mut b = 0usize;
|
||||
| ------------------- non-asm is unsupported in naked functions
|
||||
LL | let mut c = 0usize;
|
||||
| ------------------- non-asm is unsupported in naked functions
|
||||
LL | let mut d = 0usize;
|
||||
| ------------------- non-asm is unsupported in naked functions
|
||||
LL | let mut e = 0usize;
|
||||
| ------------------- non-asm is unsupported in naked functions
|
||||
|
||||
error[E0787]: naked functions must contain a single asm block
|
||||
--> $DIR/naked-functions.rs:77:1
|
||||
|
|
||||
LL | / pub extern "C" fn missing_assembly() {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | pub extern "C" fn missing_assembly() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0787]: asm in naked functions must use `noreturn` option
|
||||
--> $DIR/naked-functions.rs:84:5
|
||||
@ -185,20 +177,17 @@ LL | asm!("", options(noreturn));
|
||||
error[E0787]: naked functions must contain a single asm block
|
||||
--> $DIR/naked-functions.rs:82:1
|
||||
|
|
||||
LL | / pub extern "C" fn too_many_asm_blocks() {
|
||||
LL | |
|
||||
LL | | asm!("");
|
||||
LL | |
|
||||
LL | | asm!("");
|
||||
| | -------- multiple asm blocks are unsupported in naked functions
|
||||
LL | |
|
||||
LL | | asm!("");
|
||||
| | -------- multiple asm blocks are unsupported in naked functions
|
||||
LL | |
|
||||
LL | | asm!("", options(noreturn));
|
||||
| | --------------------------- multiple asm blocks are unsupported in naked functions
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | pub extern "C" fn too_many_asm_blocks() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
...
|
||||
LL | asm!("");
|
||||
| -------- multiple asm blocks are unsupported in naked functions
|
||||
LL |
|
||||
LL | asm!("");
|
||||
| -------- multiple asm blocks are unsupported in naked functions
|
||||
LL |
|
||||
LL | asm!("", options(noreturn));
|
||||
| --------------------------- multiple asm blocks are unsupported in naked functions
|
||||
|
||||
error: referencing function parameters is not allowed in naked functions
|
||||
--> $DIR/naked-functions.rs:97:11
|
||||
@ -211,13 +200,11 @@ LL | *&y
|
||||
error[E0787]: naked functions must contain a single asm block
|
||||
--> $DIR/naked-functions.rs:95:5
|
||||
|
|
||||
LL | / pub extern "C" fn inner(y: usize) -> usize {
|
||||
LL | |
|
||||
LL | | *&y
|
||||
| | --- non-asm is unsupported in naked functions
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^
|
||||
LL | pub extern "C" fn inner(y: usize) -> usize {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | *&y
|
||||
| --- non-asm is unsupported in naked functions
|
||||
|
||||
error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
|
||||
--> $DIR/naked-functions.rs:105:5
|
||||
@ -249,18 +236,18 @@ LL | asm!("", options(noreturn, may_unwind));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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() {
|
||||
| ^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(undefined_naked_function_abi)]` on by default
|
||||
|
||||
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() {
|
||||
| ^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: naked functions cannot be inlined
|
||||
--> $DIR/naked-functions.rs:170:1
|
||||
|
@ -4,5 +4,5 @@ trait I32Iterator = Iterator<Item = i32>;
|
||||
|
||||
fn main() {
|
||||
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`
|
||||
}
|
||||
|
@ -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
|
||||
|
|
||||
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
|
||||
|
@ -15,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 {
|
||||
return 0u8;
|
||||
};
|
||||
let _: &dyn Future<Output = ()> = █
|
||||
//~^ 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 {
|
||||
@ -24,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 {
|
||||
return 0u8;
|
||||
};
|
||||
let _: &dyn Future<Output = ()> = █
|
||||
//~^ 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() {
|
||||
@ -42,7 +42,9 @@ fn no_break_in_async_block_even_with_outer_loop() {
|
||||
}
|
||||
|
||||
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> {
|
||||
//~^ ERROR mismatched types
|
||||
|
@ -31,7 +31,7 @@ LL | |
|
||||
LL | | }
|
||||
| |_^ 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
|
||||
|
|
||||
LL | let _: &dyn Future<Output = ()> = █
|
||||
@ -47,7 +47,7 @@ LL | fn return_targets_async_block_not_fn() -> u8 {
|
||||
| |
|
||||
| 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
|
||||
|
|
||||
LL | let _: &dyn Future<Output = ()> = █
|
||||
@ -56,7 +56,7 @@ LL | let _: &dyn Future<Output = ()> = █
|
||||
= note: required for the cast from `impl Future<Output = u8>` to the object type `dyn Future<Output = ()>`
|
||||
|
||||
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> {
|
||||
| ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
|
||||
@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result<u8, MyErr> {
|
||||
found unit type `()`
|
||||
|
||||
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> {
|
||||
| ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
|
||||
|
@ -6,9 +6,9 @@
|
||||
enum Eu64 {
|
||||
//~^ ERROR discriminant value `0` assigned more than once
|
||||
Au64 = 0,
|
||||
//~^NOTE first assignment of `0`
|
||||
//~^NOTE `0` assigned here
|
||||
Bu64 = 0x8000_0000_0000_0000
|
||||
//~^NOTE second assignment of `0` (overflowed from `9223372036854775808`)
|
||||
//~^NOTE `0` (overflowed from `9223372036854775808`) assigned here
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -5,10 +5,10 @@ LL | enum Eu64 {
|
||||
| ^^^^^^^^^
|
||||
LL |
|
||||
LL | Au64 = 0,
|
||||
| - first assignment of `0`
|
||||
| - `0` assigned here
|
||||
LL |
|
||||
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
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
enum Enum {
|
||||
//~^ ERROR discriminant value `3` assigned more than once
|
||||
P = 3,
|
||||
//~^ NOTE first assignment of `3`
|
||||
//~^ NOTE `3` assigned here
|
||||
X = 3,
|
||||
//~^ NOTE second assignment of `3`
|
||||
//~^ NOTE `3` assigned here
|
||||
Y = 5
|
||||
}
|
||||
|
||||
@ -11,20 +11,43 @@ enum Enum {
|
||||
enum EnumOverflowRepr {
|
||||
//~^ ERROR discriminant value `1` assigned more than once
|
||||
P = 257,
|
||||
//~^ NOTE first assignment of `1` (overflowed from `257`)
|
||||
//~^ NOTE `1` (overflowed from `257`) assigned here
|
||||
X = 513,
|
||||
//~^ NOTE second assignment of `1` (overflowed from `513`)
|
||||
//~^ NOTE `1` (overflowed from `513`) assigned here
|
||||
}
|
||||
|
||||
#[repr(i8)]
|
||||
enum NegDisEnum {
|
||||
//~^ ERROR discriminant value `-1` assigned more than once
|
||||
First = -1,
|
||||
//~^ NOTE first assignment of `-1`
|
||||
//~^ NOTE `-1` assigned here
|
||||
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,
|
||||
//~^ 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() {
|
||||
|
@ -5,10 +5,10 @@ LL | enum Enum {
|
||||
| ^^^^^^^^^
|
||||
LL |
|
||||
LL | P = 3,
|
||||
| - first assignment of `3`
|
||||
| - `3` assigned here
|
||||
LL |
|
||||
LL | X = 3,
|
||||
| - second assignment of `3`
|
||||
| - `3` assigned here
|
||||
|
||||
error[E0081]: discriminant value `1` assigned more than once
|
||||
--> $DIR/E0081.rs:11:1
|
||||
@ -17,10 +17,10 @@ LL | enum EnumOverflowRepr {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | P = 257,
|
||||
| --- first assignment of `1` (overflowed from `257`)
|
||||
| --- `1` (overflowed from `257`) assigned here
|
||||
LL |
|
||||
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
|
||||
--> $DIR/E0081.rs:20:1
|
||||
@ -29,14 +29,50 @@ LL | enum NegDisEnum {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | First = -1,
|
||||
| -- first assignment of `-1`
|
||||
| -- `-1` assigned here
|
||||
LL |
|
||||
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 | 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`.
|
||||
|
@ -38,9 +38,13 @@ fn main() {
|
||||
let v = Unit2.m(
|
||||
//~^ ERROR type mismatch
|
||||
L {
|
||||
//~^ ERROR type mismatch
|
||||
f : |x| { drop(x); Unit4 }
|
||||
});
|
||||
//~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
|
||||
f: |x| {
|
||||
drop(x);
|
||||
Unit4
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
impl<'a> Ty<'a> for Unit2 {
|
||||
|
@ -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
|
||||
|
|
||||
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`
|
||||
--> $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>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^ 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
|
||||
|
|
||||
LL | let v = Unit2.m(
|
||||
@ -30,11 +30,14 @@ LL | let v = Unit2.m(
|
||||
LL |
|
||||
LL | / L {
|
||||
LL | |
|
||||
LL | | f : |x| { drop(x); Unit4 }
|
||||
LL | | });
|
||||
LL | | f: |x| {
|
||||
LL | | drop(x);
|
||||
LL | | Unit4
|
||||
LL | | },
|
||||
LL | | },
|
||||
| |_________^ 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
|
||||
|
|
||||
LL | impl<'a, A, T> T0<'a, A> for L<T>
|
||||
|
@ -7,7 +7,7 @@ type F = impl core::future::Future<Output = u8>;
|
||||
struct Bug {
|
||||
V1: [(); {
|
||||
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 {}
|
||||
}
|
||||
let f: F = async { 1 };
|
||||
|
@ -16,7 +16,7 @@ LL | let f: F = async { 1 };
|
||||
LL | }],
|
||||
| - 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
|
||||
|
|
||||
LL | fn concrete_use() -> F {
|
||||
|
@ -27,7 +27,7 @@ fn baz(n: bool) -> i32 {
|
||||
|
||||
const fn return_ty_mismatch() {
|
||||
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() {
|
||||
|
@ -51,7 +51,7 @@ note: required by a bound in `const_eval_select`
|
||||
LL | G: FnOnce<ARG, Output = RET> + ~const Destruct,
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ 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
|
||||
|
|
||||
LL | const_eval_select((1,), foo, bar);
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -3,12 +3,13 @@ use std::vec::IntoIter;
|
||||
pub fn get_tok(it: &mut IntoIter<u8>) {
|
||||
let mut found_e = false;
|
||||
|
||||
let temp: Vec<u8> = it.take_while(|&x| {
|
||||
found_e = true;
|
||||
false
|
||||
})
|
||||
let temp: Vec<u8> = it
|
||||
.take_while(|&x| {
|
||||
found_e = true;
|
||||
false
|
||||
})
|
||||
.cloned()
|
||||
//~^ ERROR type mismatch resolving
|
||||
//~^ ERROR to be an iterator that yields `&_`, but it yields `u8`
|
||||
.collect(); //~ ERROR the method
|
||||
}
|
||||
|
||||
|
@ -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 == &_`
|
||||
--> $DIR/issue-31173.rs:10:10
|
||||
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:11:10
|
||||
|
|
||||
LL | .cloned()
|
||||
| ^^^^^^ expected reference, found `u8`
|
||||
@ -12,11 +12,11 @@ note: required by a bound in `cloned`
|
||||
LL | Self: Sized + Iterator<Item = &'a T>,
|
||||
| ^^^^^^^^^^^^ 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
|
||||
--> $DIR/issue-31173.rs:12:10
|
||||
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:13:10
|
||||
|
|
||||
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
|
||||
|
|
||||
@ -29,10 +29,10 @@ LL | pub struct TakeWhile<I, P> {
|
||||
| -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
|
||||
|
|
||||
= 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 = &_`
|
||||
which is required by `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:6:39: 6:43]>>: Iterator`
|
||||
which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
|
||||
`<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:7:21: 7:25]>>: 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:7:21: 7:25]>>: Iterator`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn main() {
|
||||
for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
|
||||
//~^ ERROR type mismatch
|
||||
//~| 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 expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
|
||||
//~| ERROR expected `std::collections::hash_map::Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)`
|
||||
}
|
||||
|
@ -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
|
||||
|
|
||||
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>,
|
||||
| ^^^^^^^^^^^^ 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
|
||||
|
|
||||
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 `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
|
||||
|
|
||||
LL | for _ in HashMap::new().iter().cloned() {}
|
||||
|
18
src/test/ui/macros/auxiliary/issue-100199.rs
Normal file
18
src/test/ui/macros/auxiliary/issue-100199.rs
Normal 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> {}
|
||||
)
|
||||
}
|
16
src/test/ui/macros/issue-100199.rs
Normal file
16
src/test/ui/macros/issue-100199.rs
Normal 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() {}
|
15
src/test/ui/macros/issue-100199.stderr
Normal file
15
src/test/ui/macros/issue-100199.stderr
Normal 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`.
|
@ -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
|
||||
|
|
||||
LL | let error = Closure::wrap(Box::new(move || {
|
||||
|
@ -16,7 +16,7 @@ use std::marker::PhantomData;
|
||||
|
||||
fn main() {
|
||||
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.");
|
||||
}) as Box<dyn FnMut()>);
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
|
||||
Some(1) => {}
|
||||
// hello
|
||||
Some(_) => {}
|
||||
None => todo!()
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
// run-rustfix
|
||||
|
||||
fn main() {
|
||||
match Some(1) { //~ ERROR non-exhaustive patterns: `None` not covered
|
||||
Some(1) => {}
|
||||
// hello
|
||||
Some(_) => {}
|
||||
}
|
||||
}
|
@ -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`.
|
19
src/test/ui/proc-macro/auxiliary/re-export.rs
Normal file
19
src/test/ui/proc-macro/auxiliary/re-export.rs
Normal 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()
|
||||
}
|
10
src/test/ui/proc-macro/issue-79148.rs
Normal file
10
src/test/ui/proc-macro/issue-79148.rs
Normal 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() {}
|
16
src/test/ui/proc-macro/issue-79148.stderr
Normal file
16
src/test/ui/proc-macro/issue-79148.stderr
Normal 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`.
|
29
src/test/ui/stability-attribute/auxiliary/default_body.rs
Normal file
29
src/test/ui/stability-attribute/auxiliary/default_body.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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`.
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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() { }
|
@ -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`.
|
@ -4,13 +4,13 @@
|
||||
|
||||
use std::vec::IntoIter;
|
||||
|
||||
pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
|
||||
pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
|
||||
type Key;
|
||||
}
|
||||
|
||||
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() {}
|
||||
|
@ -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
|
||||
|
|
||||
LL | type Key = u32;
|
||||
@ -7,8 +7,8 @@ LL | type Key = u32;
|
||||
note: required by a bound in `Foo`
|
||||
--> $DIR/assoc-type-in-superbad.rs:7:25
|
||||
|
|
||||
LL | pub trait Foo: Iterator<Item=<Self as Foo>::Key> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
|
||||
LL | pub trait Foo: Iterator<Item = <Self as Foo>::Key> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -8,7 +8,7 @@ trait Foo {
|
||||
|
||||
impl Foo for () {
|
||||
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() {
|
||||
|
@ -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
|
||||
|
|
||||
LL | type X = impl Sized;
|
||||
|
@ -1,13 +1,11 @@
|
||||
// edition:2018
|
||||
|
||||
type AsyncFnPtr = Box<
|
||||
dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>,
|
||||
>;
|
||||
type AsyncFnPtr = Box<dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>>;
|
||||
|
||||
async fn test() {}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
fn main() {
|
||||
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 = ()>`
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>`
|
||||
--> $DIR/issue-98604.rs:11:5
|
||||
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:9:5
|
||||
|
|
||||
LL | Box::new(test) as AsyncFnPtr;
|
||||
| ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
|
||||
|
|
||||
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() {}
|
||||
| ^ checked the `Output` of this `async fn`, found opaque type
|
||||
|
@ -1,8 +1,10 @@
|
||||
fn hi() -> impl Sized { std::ptr::null::<u8>() }
|
||||
fn hi() -> impl Sized {
|
||||
std::ptr::null::<u8>()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
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 null = *boxed;
|
||||
println!("{null:?}");
|
||||
|
@ -1,7 +1,7 @@
|
||||
error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
|
||||
--> $DIR/issue-98608.rs:4:39
|
||||
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:6:39
|
||||
|
|
||||
LL | fn hi() -> impl Sized { std::ptr::null::<u8>() }
|
||||
LL | fn hi() -> impl Sized {
|
||||
| ---------- the found opaque type
|
||||
...
|
||||
LL | let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
|
||||
|
@ -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
|
||||
|
|
||||
LL | x.read = 4;
|
||||
| - ^^^^ method, not a field
|
||||
| |
|
||||
| help: to access the field, dereference first: `(*x)`
|
||||
| ^^^^ method, not a field
|
||||
|
|
||||
help: to access the field, dereference first
|
||||
|
|
||||
LL | (*x).read = 4;
|
||||
| ++ +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -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.
|
||||
-->
|
||||
|
||||
**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`)
|
||||
|
||||
|
@ -18,6 +18,7 @@ env:
|
||||
FETCH_DEPTH: 0 # pull in the tags for the version string
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.15
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
||||
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
|
||||
|
||||
jobs:
|
||||
dist:
|
||||
@ -36,6 +37,9 @@ jobs:
|
||||
- os: ubuntu-18.04
|
||||
target: aarch64-unknown-linux-gnu
|
||||
code-target: linux-arm64
|
||||
- os: ubuntu-18.04
|
||||
target: arm-unknown-linux-gnueabihf
|
||||
code-target: linux-armhf
|
||||
- os: macos-11
|
||||
target: x86_64-apple-darwin
|
||||
code-target: darwin-x64
|
||||
@ -67,13 +71,17 @@ jobs:
|
||||
node-version: 14.x
|
||||
|
||||
- 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
|
||||
|
||||
- name: Install target toolchain
|
||||
- name: Install AArch64 target toolchain
|
||||
if: matrix.target == 'aarch64-unknown-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
|
||||
run: cargo xtask dist --client-patch-version ${{ github.run_number }}
|
||||
|
||||
@ -204,6 +212,10 @@ jobs:
|
||||
with:
|
||||
name: dist-aarch64-unknown-linux-gnu
|
||||
path: dist
|
||||
- uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: dist-arm-unknown-linux-gnueabihf
|
||||
path: dist
|
||||
- uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: dist-x86_64-pc-windows-msvc
|
||||
|
@ -43,7 +43,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
|
||||
|
||||
## 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).
|
||||
|
||||
See LICENSE-APACHE and LICENSE-MIT for details.
|
||||
|
@ -57,6 +57,7 @@ pub struct FlycheckHandle {
|
||||
// XXX: drop order is significant
|
||||
sender: Sender<Restart>,
|
||||
_thread: jod_thread::JoinHandle,
|
||||
id: usize,
|
||||
}
|
||||
|
||||
impl FlycheckHandle {
|
||||
@ -72,18 +73,22 @@ impl FlycheckHandle {
|
||||
.name("Flycheck".to_owned())
|
||||
.spawn(move || actor.run(receiver))
|
||||
.expect("failed to spawn thread");
|
||||
FlycheckHandle { sender, _thread: thread }
|
||||
FlycheckHandle { id, sender, _thread: thread }
|
||||
}
|
||||
|
||||
/// Schedule a re-start of the cargo check worker.
|
||||
pub fn update(&self) {
|
||||
self.sender.send(Restart).unwrap();
|
||||
}
|
||||
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Message {
|
||||
/// 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
|
||||
Progress {
|
||||
@ -96,8 +101,9 @@ pub enum Message {
|
||||
impl fmt::Debug for Message {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Message::AddDiagnostic { workspace_root, diagnostic } => f
|
||||
Message::AddDiagnostic { id, workspace_root, diagnostic } => f
|
||||
.debug_struct("AddDiagnostic")
|
||||
.field("id", id)
|
||||
.field("workspace_root", workspace_root)
|
||||
.field("diagnostic_code", &diagnostic.code.as_ref().map(|it| &it.code))
|
||||
.finish(),
|
||||
@ -183,7 +189,7 @@ impl FlycheckActor {
|
||||
}
|
||||
}
|
||||
Event::CheckEvent(None) => {
|
||||
tracing::debug!("flycheck finished");
|
||||
tracing::debug!(flycheck_id = self.id, "flycheck finished");
|
||||
|
||||
// Watcher finished
|
||||
let cargo_handle = self.cargo_handle.take().unwrap();
|
||||
@ -203,6 +209,7 @@ impl FlycheckActor {
|
||||
|
||||
CargoMessage::Diagnostic(msg) => {
|
||||
self.send(Message::AddDiagnostic {
|
||||
id: self.id,
|
||||
workspace_root: self.workspace_root.clone(),
|
||||
diagnostic: msg,
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user