mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
Auto merge of #100318 - Dylan-DPC:rollup-18tzp6q, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #96478 (Implement `#[rustc_default_body_unstable]`) - #99787 (Rustdoc-Json: Document HRTB's on DynTrait) - #100181 (add method to get the mutability of an AllocId) - #100221 (Don't document impossible to call default trait items on impls) - #100228 (Don't ICE while suggesting updating item path.) - #100301 (Avoid `&str` to `String` conversions) - #100305 (Suggest adding an appropriate missing pattern excluding comments) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6d3f1beae1
@ -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
|
||||
|
@ -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),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -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,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,
|
||||
|
@ -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};
|
||||
@ -1103,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)) {
|
||||
|
@ -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(
|
||||
|
@ -121,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;
|
||||
@ -661,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>,
|
||||
|
@ -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"]):
|
||||
|
@ -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);
|
||||
}
|
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 {}
|
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`.
|
@ -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`.
|
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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user