mirror of
https://github.com/rust-lang/rust
synced 2024-10-06 08:40:35 +00:00
Auto merge of #106209 - fee1-dead-contrib:rollup-47ysdcu, r=fee1-dead
Rollup of 9 pull requests Successful merges: - #94145 (Test leaking of BinaryHeap Drain iterators) - #103945 (Remove `iter::Empty` hack) - #104024 (Fix `unused_must_use` warning for `Box::from_raw`) - #104708 (Fix backoff doc to match implementation) - #105347 (Account for `match` expr in single line) - #105484 (Implement allow-by-default `multiple_supertrait_upcastable` lint) - #106184 (Fix `core::any` docs) - #106201 (Emit fewer errors on invalid `#[repr(transparent)]` on `enum`) - #106205 (Remove some totally duplicated files in `rustc_infer`) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6a20f7df57
|
@ -160,6 +160,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
|
||||||
(active, intrinsics, "1.0.0", None, None),
|
(active, intrinsics, "1.0.0", None, None),
|
||||||
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
/// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
|
||||||
(active, lang_items, "1.0.0", None, None),
|
(active, lang_items, "1.0.0", None, None),
|
||||||
|
/// Allows the `multiple_supertrait_upcastable` lint.
|
||||||
|
(active, multiple_supertrait_upcastable, "CURRENT_RUSTC_VERSION", None, None),
|
||||||
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
||||||
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
|
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
|
||||||
/// Allows using `#[prelude_import]` on glob `use` items.
|
/// Allows using `#[prelude_import]` on glob `use` items.
|
||||||
|
|
|
@ -1060,10 +1060,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
|
||||||
|
|
||||||
if adt.variants().len() != 1 {
|
if adt.variants().len() != 1 {
|
||||||
bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
|
bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
|
||||||
if adt.variants().is_empty() {
|
// Don't bother checking the fields.
|
||||||
// Don't bother checking the fields. No variants (and thus no fields) exist.
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each field, figure out if it's known to be a ZST and align(1), with "known"
|
// For each field, figure out if it's known to be a ZST and align(1), with "known"
|
||||||
|
|
|
@ -729,7 +729,7 @@ fn note_error_origin(
|
||||||
format!("this and all prior arms are found to be of type `{}`", t),
|
format!("this and all prior arms are found to be of type `{}`", t),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let outer_error_span = if any_multiline_arm {
|
let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
|
||||||
// Cover just `match` and the scrutinee expression, not
|
// Cover just `match` and the scrutinee expression, not
|
||||||
// the entire match body, to reduce diagram noise.
|
// the entire match body, to reduce diagram noise.
|
||||||
cause.span.shrink_to_lo().to(scrut_span)
|
cause.span.shrink_to_lo().to(scrut_span)
|
||||||
|
@ -737,7 +737,7 @@ fn note_error_origin(
|
||||||
cause.span
|
cause.span
|
||||||
};
|
};
|
||||||
let msg = "`match` arms have incompatible types";
|
let msg = "`match` arms have incompatible types";
|
||||||
err.span_label(outer_error_span, msg);
|
err.span_label(outer, msg);
|
||||||
self.suggest_remove_semi_or_return_binding(
|
self.suggest_remove_semi_or_return_binding(
|
||||||
err,
|
err,
|
||||||
prior_arm_block_id,
|
prior_arm_block_id,
|
||||||
|
|
|
@ -1,427 +0,0 @@
|
||||||
use crate::errors::RegionOriginNote;
|
|
||||||
use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
|
|
||||||
use crate::infer::{self, SubregionOrigin};
|
|
||||||
use rustc_errors::{
|
|
||||||
fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
|
||||||
};
|
|
||||||
use rustc_middle::traits::ObligationCauseCode;
|
|
||||||
use rustc_middle::ty::error::TypeError;
|
|
||||||
use rustc_middle::ty::{self, Region};
|
|
||||||
|
|
||||||
use super::ObligationCauseAsDiagArg;
|
|
||||||
|
|
||||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|
||||||
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
|
|
||||||
match *origin {
|
|
||||||
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
|
||||||
span: trace.cause.span,
|
|
||||||
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
|
|
||||||
expected_found: self.values_str(trace.values),
|
|
||||||
}
|
|
||||||
.add_to_diagnostic(err),
|
|
||||||
infer::Reborrow(span) => {
|
|
||||||
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
|
|
||||||
}
|
|
||||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
|
||||||
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
|
|
||||||
RegionOriginNote::WithName {
|
|
||||||
span,
|
|
||||||
msg: fluent::infer_reborrow,
|
|
||||||
name: &var_name.to_string(),
|
|
||||||
continues: false,
|
|
||||||
}
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
infer::RelateObjectBound(span) => {
|
|
||||||
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
infer::DataBorrowed(ty, span) => {
|
|
||||||
RegionOriginNote::WithName {
|
|
||||||
span,
|
|
||||||
msg: fluent::infer_data_borrowed,
|
|
||||||
name: &self.ty_to_string(ty),
|
|
||||||
continues: false,
|
|
||||||
}
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
|
||||||
RegionOriginNote::WithName {
|
|
||||||
span,
|
|
||||||
msg: fluent::infer_reference_outlives_referent,
|
|
||||||
name: &self.ty_to_string(ty),
|
|
||||||
continues: false,
|
|
||||||
}
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
infer::RelateParamBound(span, ty, opt_span) => {
|
|
||||||
RegionOriginNote::WithName {
|
|
||||||
span,
|
|
||||||
msg: fluent::infer_relate_param_bound,
|
|
||||||
name: &self.ty_to_string(ty),
|
|
||||||
continues: opt_span.is_some(),
|
|
||||||
}
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
if let Some(span) = opt_span {
|
|
||||||
RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
infer::RelateRegionParamBound(span) => {
|
|
||||||
RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
infer::CompareImplItemObligation { span, .. } => {
|
|
||||||
RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
|
||||||
self.note_region_origin(err, &parent);
|
|
||||||
}
|
|
||||||
infer::AscribeUserTypeProvePredicate(span) => {
|
|
||||||
RegionOriginNote::Plain {
|
|
||||||
span,
|
|
||||||
msg: fluent::infer_ascribe_user_type_prove_predicate,
|
|
||||||
}
|
|
||||||
.add_to_diagnostic(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn report_concrete_failure(
|
|
||||||
&self,
|
|
||||||
origin: SubregionOrigin<'tcx>,
|
|
||||||
sub: Region<'tcx>,
|
|
||||||
sup: Region<'tcx>,
|
|
||||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
|
||||||
match origin {
|
|
||||||
infer::Subtype(box trace) => {
|
|
||||||
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
|
|
||||||
let mut err = self.report_and_explain_type_error(trace, terr);
|
|
||||||
match (*sub, *sup) {
|
|
||||||
(ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
|
|
||||||
(ty::RePlaceholder(_), _) => {
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"",
|
|
||||||
sup,
|
|
||||||
" doesn't meet the lifetime requirements",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(_, ty::RePlaceholder(_)) => {
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"the required lifetime does not necessarily outlive ",
|
|
||||||
sub,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"...does not necessarily outlive ",
|
|
||||||
sub,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::Reborrow(span) => {
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0312,
|
|
||||||
"lifetime of reference outlives lifetime of borrowed content..."
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"...the reference is valid for ",
|
|
||||||
sub,
|
|
||||||
"...",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"...but the borrowed content is only valid for ",
|
|
||||||
sup,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
|
||||||
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0313,
|
|
||||||
"lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
|
|
||||||
var_name
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"...the borrowed pointer is valid for ",
|
|
||||||
sub,
|
|
||||||
"...",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
&format!("...but `{}` is only valid for ", var_name),
|
|
||||||
sup,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::RelateObjectBound(span) => {
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0476,
|
|
||||||
"lifetime of the source pointer does not outlive lifetime bound of the \
|
|
||||||
object type"
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"object type is valid for ",
|
|
||||||
sub,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"source pointer is only valid for ",
|
|
||||||
sup,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::RelateParamBound(span, ty, opt_span) => {
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0477,
|
|
||||||
"the type `{}` does not fulfill the required lifetime",
|
|
||||||
self.ty_to_string(ty)
|
|
||||||
);
|
|
||||||
match *sub {
|
|
||||||
ty::ReStatic => note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"type must satisfy ",
|
|
||||||
sub,
|
|
||||||
if opt_span.is_some() { " as required by this binding" } else { "" },
|
|
||||||
opt_span,
|
|
||||||
),
|
|
||||||
_ => note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"type must outlive ",
|
|
||||||
sub,
|
|
||||||
if opt_span.is_some() { " as required by this binding" } else { "" },
|
|
||||||
opt_span,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::RelateRegionParamBound(span) => {
|
|
||||||
let mut err =
|
|
||||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"lifetime parameter instantiated with ",
|
|
||||||
sup,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"but lifetime parameter must outlive ",
|
|
||||||
sub,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::DataBorrowed(ty, span) => {
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0490,
|
|
||||||
"a value of type `{}` is borrowed for too long",
|
|
||||||
self.ty_to_string(ty)
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"the type is valid for ",
|
|
||||||
sub,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"but the borrow lasts for ",
|
|
||||||
sup,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
self.tcx.sess,
|
|
||||||
span,
|
|
||||||
E0491,
|
|
||||||
"in type `{}`, reference has a longer lifetime than the data it references",
|
|
||||||
self.ty_to_string(ty)
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"the pointer is valid for ",
|
|
||||||
sub,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"but the referenced data is only valid for ",
|
|
||||||
sup,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
|
|
||||||
.report_extra_impl_obligation(
|
|
||||||
span,
|
|
||||||
impl_item_def_id,
|
|
||||||
trait_item_def_id,
|
|
||||||
&format!("`{}: {}`", sup, sub),
|
|
||||||
),
|
|
||||||
infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
|
|
||||||
let mut err = self.report_concrete_failure(*parent, sub, sup);
|
|
||||||
|
|
||||||
let trait_item_span = self.tcx.def_span(trait_item_def_id);
|
|
||||||
let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
|
|
||||||
err.span_label(
|
|
||||||
trait_item_span,
|
|
||||||
format!("definition of `{}` from trait", item_name),
|
|
||||||
);
|
|
||||||
|
|
||||||
let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
|
|
||||||
let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
|
|
||||||
|
|
||||||
let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
|
|
||||||
impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
|
|
||||||
let clauses: Vec<_> = trait_predicates
|
|
||||||
.predicates
|
|
||||||
.into_iter()
|
|
||||||
.filter(|&(pred, _)| !impl_predicates.contains(pred))
|
|
||||||
.map(|(pred, _)| format!("{}", pred))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if !clauses.is_empty() {
|
|
||||||
let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
|
|
||||||
let where_clause_span = generics.tail_span_for_predicate_suggestion();
|
|
||||||
|
|
||||||
let suggestion = format!(
|
|
||||||
"{} {}",
|
|
||||||
generics.add_where_or_trailing_comma(),
|
|
||||||
clauses.join(", "),
|
|
||||||
);
|
|
||||||
err.span_suggestion(
|
|
||||||
where_clause_span,
|
|
||||||
&format!(
|
|
||||||
"try copying {} from the trait",
|
|
||||||
if clauses.len() > 1 { "these clauses" } else { "this clause" }
|
|
||||||
),
|
|
||||||
suggestion,
|
|
||||||
rustc_errors::Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
err
|
|
||||||
}
|
|
||||||
infer::AscribeUserTypeProvePredicate(span) => {
|
|
||||||
let mut err =
|
|
||||||
struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"lifetime instantiated with ",
|
|
||||||
sup,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
note_and_explain_region(
|
|
||||||
self.tcx,
|
|
||||||
&mut err,
|
|
||||||
"but lifetime must outlive ",
|
|
||||||
sub,
|
|
||||||
"",
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn report_placeholder_failure(
|
|
||||||
&self,
|
|
||||||
placeholder_origin: SubregionOrigin<'tcx>,
|
|
||||||
sub: Region<'tcx>,
|
|
||||||
sup: Region<'tcx>,
|
|
||||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
|
||||||
// I can't think how to do better than this right now. -nikomatsakis
|
|
||||||
debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
|
|
||||||
match placeholder_origin {
|
|
||||||
infer::Subtype(box ref trace)
|
|
||||||
if matches!(
|
|
||||||
&trace.cause.code().peel_derives(),
|
|
||||||
ObligationCauseCode::BindingObligation(..)
|
|
||||||
| ObligationCauseCode::ExprBindingObligation(..)
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
// Hack to get around the borrow checker because trace.cause has an `Rc`.
|
|
||||||
if let ObligationCauseCode::BindingObligation(_, span)
|
|
||||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..) =
|
|
||||||
&trace.cause.code().peel_derives()
|
|
||||||
{
|
|
||||||
let span = *span;
|
|
||||||
let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
|
|
||||||
err.span_note(span, "the lifetime requirement is introduced here");
|
|
||||||
err
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
infer::Subtype(box trace) => {
|
|
||||||
let terr = TypeError::RegionsPlaceholderMismatch;
|
|
||||||
return self.report_and_explain_type_error(trace, terr);
|
|
||||||
}
|
|
||||||
_ => return self.report_concrete_failure(placeholder_origin, sub, sup),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,203 +0,0 @@
|
||||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|
||||||
fn note_error_origin(
|
|
||||||
&self,
|
|
||||||
err: &mut Diagnostic,
|
|
||||||
cause: &ObligationCause<'tcx>,
|
|
||||||
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
|
|
||||||
terr: TypeError<'tcx>,
|
|
||||||
) {
|
|
||||||
match *cause.code() {
|
|
||||||
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
|
|
||||||
let ty = self.resolve_vars_if_possible(root_ty);
|
|
||||||
if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
|
|
||||||
{
|
|
||||||
// don't show type `_`
|
|
||||||
if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
|
|
||||||
&& let ty::Adt(def, substs) = ty.kind()
|
|
||||||
&& Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
|
|
||||||
{
|
|
||||||
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
|
|
||||||
} else {
|
|
||||||
err.span_label(span, format!("this expression has type `{}`", ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
|
|
||||||
&& ty.is_box() && ty.boxed_ty() == found
|
|
||||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
|
||||||
{
|
|
||||||
err.span_suggestion(
|
|
||||||
span,
|
|
||||||
"consider dereferencing the boxed value",
|
|
||||||
format!("*{}", snippet),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
|
|
||||||
err.span_label(span, "expected due to this");
|
|
||||||
}
|
|
||||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
|
||||||
arm_block_id,
|
|
||||||
arm_span,
|
|
||||||
arm_ty,
|
|
||||||
prior_arm_block_id,
|
|
||||||
prior_arm_span,
|
|
||||||
prior_arm_ty,
|
|
||||||
source,
|
|
||||||
ref prior_arms,
|
|
||||||
scrut_hir_id,
|
|
||||||
opt_suggest_box_span,
|
|
||||||
scrut_span,
|
|
||||||
..
|
|
||||||
}) => match source {
|
|
||||||
hir::MatchSource::TryDesugar => {
|
|
||||||
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
|
|
||||||
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
|
|
||||||
let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
|
|
||||||
let arg_expr = args.first().expect("try desugaring call w/out arg");
|
|
||||||
self.typeck_results.as_ref().and_then(|typeck_results| {
|
|
||||||
typeck_results.expr_ty_opt(arg_expr)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
bug!("try desugaring w/out call expr as scrutinee");
|
|
||||||
};
|
|
||||||
|
|
||||||
match scrut_ty {
|
|
||||||
Some(ty) if expected == ty => {
|
|
||||||
let source_map = self.tcx.sess.source_map();
|
|
||||||
err.span_suggestion(
|
|
||||||
source_map.end_point(cause.span),
|
|
||||||
"try removing this `?`",
|
|
||||||
"",
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// `prior_arm_ty` can be `!`, `expected` will have better info when present.
|
|
||||||
let t = self.resolve_vars_if_possible(match exp_found {
|
|
||||||
Some(ty::error::ExpectedFound { expected, .. }) => expected,
|
|
||||||
_ => prior_arm_ty,
|
|
||||||
});
|
|
||||||
let source_map = self.tcx.sess.source_map();
|
|
||||||
let mut any_multiline_arm = source_map.is_multiline(arm_span);
|
|
||||||
if prior_arms.len() <= 4 {
|
|
||||||
for sp in prior_arms {
|
|
||||||
any_multiline_arm |= source_map.is_multiline(*sp);
|
|
||||||
err.span_label(*sp, format!("this is found to be of type `{}`", t));
|
|
||||||
}
|
|
||||||
} else if let Some(sp) = prior_arms.last() {
|
|
||||||
any_multiline_arm |= source_map.is_multiline(*sp);
|
|
||||||
err.span_label(
|
|
||||||
*sp,
|
|
||||||
format!("this and all prior arms are found to be of type `{}`", t),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let outer_error_span = if any_multiline_arm {
|
|
||||||
// Cover just `match` and the scrutinee expression, not
|
|
||||||
// the entire match body, to reduce diagram noise.
|
|
||||||
cause.span.shrink_to_lo().to(scrut_span)
|
|
||||||
} else {
|
|
||||||
cause.span
|
|
||||||
};
|
|
||||||
let msg = "`match` arms have incompatible types";
|
|
||||||
err.span_label(outer_error_span, msg);
|
|
||||||
self.suggest_remove_semi_or_return_binding(
|
|
||||||
err,
|
|
||||||
prior_arm_block_id,
|
|
||||||
prior_arm_ty,
|
|
||||||
prior_arm_span,
|
|
||||||
arm_block_id,
|
|
||||||
arm_ty,
|
|
||||||
arm_span,
|
|
||||||
);
|
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
|
||||||
// Get return type span and point to it.
|
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
|
||||||
err,
|
|
||||||
ret_sp,
|
|
||||||
prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ObligationCauseCode::IfExpression(box IfExpressionCause {
|
|
||||||
then_id,
|
|
||||||
else_id,
|
|
||||||
then_ty,
|
|
||||||
else_ty,
|
|
||||||
outer_span,
|
|
||||||
opt_suggest_box_span,
|
|
||||||
}) => {
|
|
||||||
let then_span = self.find_block_span_from_hir_id(then_id);
|
|
||||||
let else_span = self.find_block_span_from_hir_id(else_id);
|
|
||||||
err.span_label(then_span, "expected because of this");
|
|
||||||
if let Some(sp) = outer_span {
|
|
||||||
err.span_label(sp, "`if` and `else` have incompatible types");
|
|
||||||
}
|
|
||||||
self.suggest_remove_semi_or_return_binding(
|
|
||||||
err,
|
|
||||||
Some(then_id),
|
|
||||||
then_ty,
|
|
||||||
then_span,
|
|
||||||
Some(else_id),
|
|
||||||
else_ty,
|
|
||||||
else_span,
|
|
||||||
);
|
|
||||||
if let Some(ret_sp) = opt_suggest_box_span {
|
|
||||||
self.suggest_boxing_for_return_impl_trait(
|
|
||||||
err,
|
|
||||||
ret_sp,
|
|
||||||
[then_span, else_span].into_iter(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ObligationCauseCode::LetElse => {
|
|
||||||
err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
|
|
||||||
err.help("...or use `match` instead of `let...else`");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if let ObligationCauseCode::BindingObligation(_, span)
|
|
||||||
| ObligationCauseCode::ExprBindingObligation(_, span, ..)
|
|
||||||
= cause.code().peel_derives()
|
|
||||||
&& let TypeError::RegionsPlaceholderMismatch = terr
|
|
||||||
{
|
|
||||||
err.span_note( * span,
|
|
||||||
"the lifetime requirement is introduced here");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> InferCtxt<'tcx> {
|
|
||||||
/// Given a [`hir::Block`], get the span of its last expression or
|
|
||||||
/// statement, peeling off any inner blocks.
|
|
||||||
pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
|
|
||||||
let block = block.innermost_block();
|
|
||||||
if let Some(expr) = &block.expr {
|
|
||||||
expr.span
|
|
||||||
} else if let Some(stmt) = block.stmts.last() {
|
|
||||||
// possibly incorrect trailing `;` in the else arm
|
|
||||||
stmt.span
|
|
||||||
} else {
|
|
||||||
// empty block; point at its entirety
|
|
||||||
block.span
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a [`hir::HirId`] for a block, get the span of its last expression
|
|
||||||
/// or statement, peeling off any inner blocks.
|
|
||||||
pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
|
|
||||||
match self.tcx.hir().get(hir_id) {
|
|
||||||
hir::Node::Block(blk) => self.find_block_span(blk),
|
|
||||||
// The parser was in a weird state if either of these happen, but
|
|
||||||
// it's better not to panic.
|
|
||||||
hir::Node::Expr(e) => e.span,
|
|
||||||
_ => rustc_span::DUMMY_SP,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -61,6 +61,7 @@
|
||||||
mod let_underscore;
|
mod let_underscore;
|
||||||
mod levels;
|
mod levels;
|
||||||
mod methods;
|
mod methods;
|
||||||
|
mod multiple_supertrait_upcastable;
|
||||||
mod non_ascii_idents;
|
mod non_ascii_idents;
|
||||||
mod non_fmt_panic;
|
mod non_fmt_panic;
|
||||||
mod nonstandard_style;
|
mod nonstandard_style;
|
||||||
|
@ -95,6 +96,7 @@
|
||||||
use internal::*;
|
use internal::*;
|
||||||
use let_underscore::*;
|
use let_underscore::*;
|
||||||
use methods::*;
|
use methods::*;
|
||||||
|
use multiple_supertrait_upcastable::*;
|
||||||
use non_ascii_idents::*;
|
use non_ascii_idents::*;
|
||||||
use non_fmt_panic::NonPanicFmt;
|
use non_fmt_panic::NonPanicFmt;
|
||||||
use nonstandard_style::*;
|
use nonstandard_style::*;
|
||||||
|
@ -229,6 +231,7 @@ fn lint_mod(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||||
InvalidAtomicOrdering: InvalidAtomicOrdering,
|
InvalidAtomicOrdering: InvalidAtomicOrdering,
|
||||||
NamedAsmLabels: NamedAsmLabels,
|
NamedAsmLabels: NamedAsmLabels,
|
||||||
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
||||||
|
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
63
compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
Normal file
63
compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
|
use rustc_errors::DelayDm;
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple
|
||||||
|
/// supertraits.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// trait A {}
|
||||||
|
/// trait B {}
|
||||||
|
///
|
||||||
|
/// #[warn(multiple_supertrait_upcastable)]
|
||||||
|
/// trait C: A + B {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// To support upcasting with multiple supertraits, we need to store multiple vtables and this
|
||||||
|
/// can result in extra space overhead, even if no code actually uses upcasting.
|
||||||
|
/// This lint allows users to identify when such scenarios occur and to decide whether the
|
||||||
|
/// additional overhead is justified.
|
||||||
|
pub MULTIPLE_SUPERTRAIT_UPCASTABLE,
|
||||||
|
Allow,
|
||||||
|
"detect when an object-safe trait has multiple supertraits",
|
||||||
|
@feature_gate = sym::multiple_supertrait_upcastable;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTABLE]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
|
||||||
|
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||||
|
let def_id = item.owner_id.to_def_id();
|
||||||
|
if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
|
||||||
|
&& cx.tcx.is_object_safe(def_id)
|
||||||
|
{
|
||||||
|
let direct_super_traits_iter = cx.tcx
|
||||||
|
.super_predicates_of(def_id)
|
||||||
|
.predicates
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(pred, _)| pred.to_opt_poly_trait_pred());
|
||||||
|
if direct_super_traits_iter.count() > 1 {
|
||||||
|
cx.struct_span_lint(
|
||||||
|
MULTIPLE_SUPERTRAIT_UPCASTABLE,
|
||||||
|
cx.tcx.def_span(def_id),
|
||||||
|
DelayDm(|| {
|
||||||
|
format!(
|
||||||
|
"`{}` is object-safe and has multiple supertraits",
|
||||||
|
item.ident,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|diag| diag,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -943,6 +943,7 @@
|
||||||
mul,
|
mul,
|
||||||
mul_assign,
|
mul_assign,
|
||||||
mul_with_overflow,
|
mul_with_overflow,
|
||||||
|
multiple_supertrait_upcastable,
|
||||||
must_not_suspend,
|
must_not_suspend,
|
||||||
must_use,
|
must_use,
|
||||||
naked,
|
naked,
|
||||||
|
|
|
@ -954,7 +954,7 @@ impl<T: ?Sized> Box<T> {
|
||||||
/// [`Layout`]: crate::Layout
|
/// [`Layout`]: crate::Layout
|
||||||
#[stable(feature = "box_raw", since = "1.4.0")]
|
#[stable(feature = "box_raw", since = "1.4.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `Box`"]
|
#[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
|
||||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||||
unsafe { Self::from_raw_in(raw, Global) }
|
unsafe { Self::from_raw_in(raw, Global) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::boxed::Box;
|
use crate::boxed::Box;
|
||||||
|
use crate::testing::crash_test::{CrashTestDummy, Panic};
|
||||||
use std::iter::TrustedLen;
|
use std::iter::TrustedLen;
|
||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iterator() {
|
fn test_iterator() {
|
||||||
|
@ -291,33 +291,83 @@ fn test_drain_sorted() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_drain_sorted_leak() {
|
fn test_drain_sorted_leak() {
|
||||||
static DROPS: AtomicU32 = AtomicU32::new(0);
|
let d0 = CrashTestDummy::new(0);
|
||||||
|
let d1 = CrashTestDummy::new(1);
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
|
let d2 = CrashTestDummy::new(2);
|
||||||
struct D(u32, bool);
|
let d3 = CrashTestDummy::new(3);
|
||||||
|
let d4 = CrashTestDummy::new(4);
|
||||||
impl Drop for D {
|
let d5 = CrashTestDummy::new(5);
|
||||||
fn drop(&mut self) {
|
|
||||||
DROPS.fetch_add(1, Ordering::SeqCst);
|
|
||||||
|
|
||||||
if self.1 {
|
|
||||||
panic!("panic in `drop`");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut q = BinaryHeap::from(vec![
|
let mut q = BinaryHeap::from(vec![
|
||||||
D(0, false),
|
d0.spawn(Panic::Never),
|
||||||
D(1, false),
|
d1.spawn(Panic::Never),
|
||||||
D(2, false),
|
d2.spawn(Panic::Never),
|
||||||
D(3, true),
|
d3.spawn(Panic::InDrop),
|
||||||
D(4, false),
|
d4.spawn(Panic::Never),
|
||||||
D(5, false),
|
d5.spawn(Panic::Never),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).ok();
|
catch_unwind(AssertUnwindSafe(|| drop(q.drain_sorted()))).unwrap_err();
|
||||||
|
|
||||||
assert_eq!(DROPS.load(Ordering::SeqCst), 6);
|
assert_eq!(d0.dropped(), 1);
|
||||||
|
assert_eq!(d1.dropped(), 1);
|
||||||
|
assert_eq!(d2.dropped(), 1);
|
||||||
|
assert_eq!(d3.dropped(), 1);
|
||||||
|
assert_eq!(d4.dropped(), 1);
|
||||||
|
assert_eq!(d5.dropped(), 1);
|
||||||
|
assert!(q.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_drain_forget() {
|
||||||
|
let a = CrashTestDummy::new(0);
|
||||||
|
let b = CrashTestDummy::new(1);
|
||||||
|
let c = CrashTestDummy::new(2);
|
||||||
|
let mut q =
|
||||||
|
BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]);
|
||||||
|
|
||||||
|
catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
let mut it = q.drain();
|
||||||
|
it.next();
|
||||||
|
mem::forget(it);
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
// Behaviour after leaking is explicitly unspecified and order is arbitrary,
|
||||||
|
// so it's fine if these start failing, but probably worth knowing.
|
||||||
|
assert!(q.is_empty());
|
||||||
|
assert_eq!(a.dropped() + b.dropped() + c.dropped(), 1);
|
||||||
|
assert_eq!(a.dropped(), 0);
|
||||||
|
assert_eq!(b.dropped(), 0);
|
||||||
|
assert_eq!(c.dropped(), 1);
|
||||||
|
drop(q);
|
||||||
|
assert_eq!(a.dropped(), 0);
|
||||||
|
assert_eq!(b.dropped(), 0);
|
||||||
|
assert_eq!(c.dropped(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_drain_sorted_forget() {
|
||||||
|
let a = CrashTestDummy::new(0);
|
||||||
|
let b = CrashTestDummy::new(1);
|
||||||
|
let c = CrashTestDummy::new(2);
|
||||||
|
let mut q =
|
||||||
|
BinaryHeap::from(vec![a.spawn(Panic::Never), b.spawn(Panic::Never), c.spawn(Panic::Never)]);
|
||||||
|
|
||||||
|
catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
let mut it = q.drain_sorted();
|
||||||
|
it.next();
|
||||||
|
mem::forget(it);
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
// Behaviour after leaking is explicitly unspecified,
|
||||||
|
// so it's fine if these start failing, but probably worth knowing.
|
||||||
|
assert_eq!(q.len(), 2);
|
||||||
|
assert_eq!(a.dropped(), 0);
|
||||||
|
assert_eq!(b.dropped(), 0);
|
||||||
|
assert_eq!(c.dropped(), 1);
|
||||||
|
drop(q);
|
||||||
|
assert_eq!(a.dropped(), 1);
|
||||||
|
assert_eq!(b.dropped(), 1);
|
||||||
|
assert_eq!(c.dropped(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use super::super::testing::crash_test::{CrashTestDummy, Panic};
|
|
||||||
use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor};
|
|
||||||
use super::super::testing::rng::DeterministicRng;
|
|
||||||
use super::Entry::{Occupied, Vacant};
|
use super::Entry::{Occupied, Vacant};
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::boxed::Box;
|
use crate::boxed::Box;
|
||||||
use crate::fmt::Debug;
|
use crate::fmt::Debug;
|
||||||
use crate::rc::Rc;
|
use crate::rc::Rc;
|
||||||
use crate::string::{String, ToString};
|
use crate::string::{String, ToString};
|
||||||
|
use crate::testing::crash_test::{CrashTestDummy, Panic};
|
||||||
|
use crate::testing::ord_chaos::{Cyclic3, Governed, Governor};
|
||||||
|
use crate::testing::rng::DeterministicRng;
|
||||||
use crate::vec::Vec;
|
use crate::vec::Vec;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
|
@ -21,6 +21,3 @@ trait Recover<Q: ?Sized> {
|
||||||
fn take(&mut self, key: &Q) -> Option<Self::Key>;
|
fn take(&mut self, key: &Q) -> Option<Self::Key>;
|
||||||
fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
|
fn replace(&mut self, key: Self::Key) -> Option<Self::Key>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod testing;
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::super::testing::crash_test::{CrashTestDummy, Panic};
|
|
||||||
use super::super::testing::rng::DeterministicRng;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::testing::crash_test::{CrashTestDummy, Panic};
|
||||||
|
use crate::testing::rng::DeterministicRng;
|
||||||
use crate::vec::Vec;
|
use crate::vec::Vec;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::testing::crash_test::{CrashTestDummy, Panic};
|
||||||
use crate::vec::Vec;
|
use crate::vec::Vec;
|
||||||
|
|
||||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||||
|
@ -984,35 +985,34 @@ fn drain_filter_complex() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn drain_filter_drop_panic_leak() {
|
fn drain_filter_drop_panic_leak() {
|
||||||
static mut DROPS: i32 = 0;
|
let d0 = CrashTestDummy::new(0);
|
||||||
|
let d1 = CrashTestDummy::new(1);
|
||||||
struct D(bool);
|
let d2 = CrashTestDummy::new(2);
|
||||||
|
let d3 = CrashTestDummy::new(3);
|
||||||
impl Drop for D {
|
let d4 = CrashTestDummy::new(4);
|
||||||
fn drop(&mut self) {
|
let d5 = CrashTestDummy::new(5);
|
||||||
unsafe {
|
let d6 = CrashTestDummy::new(6);
|
||||||
DROPS += 1;
|
let d7 = CrashTestDummy::new(7);
|
||||||
}
|
|
||||||
|
|
||||||
if self.0 {
|
|
||||||
panic!("panic in `drop`");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut q = LinkedList::new();
|
let mut q = LinkedList::new();
|
||||||
q.push_back(D(false));
|
q.push_back(d3.spawn(Panic::Never));
|
||||||
q.push_back(D(false));
|
q.push_back(d4.spawn(Panic::Never));
|
||||||
q.push_back(D(false));
|
q.push_back(d5.spawn(Panic::Never));
|
||||||
q.push_back(D(false));
|
q.push_back(d6.spawn(Panic::Never));
|
||||||
q.push_back(D(false));
|
q.push_back(d7.spawn(Panic::Never));
|
||||||
q.push_front(D(false));
|
q.push_front(d2.spawn(Panic::Never));
|
||||||
q.push_front(D(true));
|
q.push_front(d1.spawn(Panic::InDrop));
|
||||||
q.push_front(D(false));
|
q.push_front(d0.spawn(Panic::Never));
|
||||||
|
|
||||||
catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).ok();
|
catch_unwind(AssertUnwindSafe(|| drop(q.drain_filter(|_| true)))).unwrap_err();
|
||||||
|
|
||||||
assert_eq!(unsafe { DROPS }, 8);
|
assert_eq!(d0.dropped(), 1);
|
||||||
|
assert_eq!(d1.dropped(), 1);
|
||||||
|
assert_eq!(d2.dropped(), 1);
|
||||||
|
assert_eq!(d3.dropped(), 1);
|
||||||
|
assert_eq!(d4.dropped(), 1);
|
||||||
|
assert_eq!(d5.dropped(), 1);
|
||||||
|
assert_eq!(d6.dropped(), 1);
|
||||||
|
assert_eq!(d7.dropped(), 1);
|
||||||
assert!(q.is_empty());
|
assert!(q.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@
|
||||||
#![warn(missing_debug_implementations)]
|
#![warn(missing_debug_implementations)]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![allow(explicit_outlives_requirements)]
|
#![allow(explicit_outlives_requirements)]
|
||||||
|
#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
|
||||||
//
|
//
|
||||||
// Library features:
|
// Library features:
|
||||||
#![feature(alloc_layout_extra)]
|
#![feature(alloc_layout_extra)]
|
||||||
|
@ -190,6 +191,7 @@
|
||||||
#![feature(unsized_fn_params)]
|
#![feature(unsized_fn_params)]
|
||||||
#![feature(c_unwind)]
|
#![feature(c_unwind)]
|
||||||
#![feature(with_negative_coherence)]
|
#![feature(with_negative_coherence)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
|
||||||
//
|
//
|
||||||
// Rustdoc features:
|
// Rustdoc features:
|
||||||
#![feature(doc_cfg)]
|
#![feature(doc_cfg)]
|
||||||
|
@ -206,6 +208,8 @@
|
||||||
extern crate std;
|
extern crate std;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod testing;
|
||||||
|
|
||||||
// Module with internal macros used by other modules (needs to be included before other modules).
|
// Module with internal macros used by other modules (needs to be included before other modules).
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then
|
//! In this example, if the concrete type of `obj` in `use_my_trait` is `SomeConcreteType`, then
|
||||||
//! the `get_context_ref` call will return a reference to `obj.some_string` with type `&String`.
|
//! the `get_context_by_ref` call will return a reference to `obj.some_string` with type `&String`.
|
||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
|
#[cfg_attr(not(test), rustc_diagnostic_item = "Error")]
|
||||||
#[rustc_has_incoherent_inherent_impls]
|
#[rustc_has_incoherent_inherent_impls]
|
||||||
|
#[cfg_attr(not(bootstrap), allow(multiple_supertrait_upcastable))]
|
||||||
pub trait Error: Debug + Display {
|
pub trait Error: Debug + Display {
|
||||||
/// The lower-level source of this error, if any.
|
/// The lower-level source of this error, if any.
|
||||||
///
|
///
|
||||||
|
|
|
@ -22,17 +22,12 @@ pub const fn empty<T>() -> Empty<T> {
|
||||||
Empty(marker::PhantomData)
|
Empty(marker::PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Newtype for use in `PhantomData` to avoid
|
|
||||||
// > error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
|
|
||||||
// in `const fn empty<T>()` above.
|
|
||||||
struct FnReturning<T>(fn() -> T);
|
|
||||||
|
|
||||||
/// An iterator that yields nothing.
|
/// An iterator that yields nothing.
|
||||||
///
|
///
|
||||||
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
|
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
|
||||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||||
#[stable(feature = "iter_empty", since = "1.2.0")]
|
#[stable(feature = "iter_empty", since = "1.2.0")]
|
||||||
pub struct Empty<T>(marker::PhantomData<FnReturning<T>>);
|
pub struct Empty<T>(marker::PhantomData<fn() -> T>);
|
||||||
|
|
||||||
#[stable(feature = "core_impl_debug", since = "1.9.0")]
|
#[stable(feature = "core_impl_debug", since = "1.9.0")]
|
||||||
impl<T> fmt::Debug for Empty<T> {
|
impl<T> fmt::Debug for Empty<T> {
|
||||||
|
|
|
@ -95,6 +95,7 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![allow(explicit_outlives_requirements)]
|
#![allow(explicit_outlives_requirements)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
#![cfg_attr(not(bootstrap), warn(multiple_supertrait_upcastable))]
|
||||||
//
|
//
|
||||||
// Library features:
|
// Library features:
|
||||||
#![feature(const_align_offset)]
|
#![feature(const_align_offset)]
|
||||||
|
@ -231,6 +232,7 @@
|
||||||
#![feature(unsized_fn_params)]
|
#![feature(unsized_fn_params)]
|
||||||
#![feature(asm_const)]
|
#![feature(asm_const)]
|
||||||
#![feature(const_transmute_copy)]
|
#![feature(const_transmute_copy)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(multiple_supertrait_upcastable))]
|
||||||
//
|
//
|
||||||
// Target features:
|
// Target features:
|
||||||
#![feature(arm_target_feature)]
|
#![feature(arm_target_feature)]
|
||||||
|
|
|
@ -136,7 +136,7 @@ pub fn snooze(&self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if exponential backoff has completed and blocking the thread is advised.
|
/// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_completed(&self) -> bool {
|
pub fn is_completed(&self) -> bool {
|
||||||
self.step.get() > YIELD_LIMIT
|
self.step.get() > YIELD_LIMIT
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![deny(multiple_supertrait_upcastable)]
|
||||||
|
//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
//~| WARNING unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
//~| WARNING unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
#![warn(multiple_supertrait_upcastable)]
|
||||||
|
//~^ WARNING unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
//~| WARNING unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
//~| WARNING unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,57 @@
|
||||||
|
warning: unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
--> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
|
||||||
|
|
|
||||||
|
LL | #![deny(multiple_supertrait_upcastable)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the `multiple_supertrait_upcastable` lint is unstable
|
||||||
|
= help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
|
||||||
|
= note: `#[warn(unknown_lints)]` on by default
|
||||||
|
|
||||||
|
warning: unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
--> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
|
||||||
|
|
|
||||||
|
LL | #![warn(multiple_supertrait_upcastable)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the `multiple_supertrait_upcastable` lint is unstable
|
||||||
|
= help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
warning: unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
--> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
|
||||||
|
|
|
||||||
|
LL | #![deny(multiple_supertrait_upcastable)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the `multiple_supertrait_upcastable` lint is unstable
|
||||||
|
= help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
warning: unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
--> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
|
||||||
|
|
|
||||||
|
LL | #![warn(multiple_supertrait_upcastable)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the `multiple_supertrait_upcastable` lint is unstable
|
||||||
|
= help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
warning: unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
--> $DIR/feature-gate-multiple_supertrait_upcastable.rs:3:1
|
||||||
|
|
|
||||||
|
LL | #![deny(multiple_supertrait_upcastable)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the `multiple_supertrait_upcastable` lint is unstable
|
||||||
|
= help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
warning: unknown lint: `multiple_supertrait_upcastable`
|
||||||
|
--> $DIR/feature-gate-multiple_supertrait_upcastable.rs:7:1
|
||||||
|
|
|
||||||
|
LL | #![warn(multiple_supertrait_upcastable)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: the `multiple_supertrait_upcastable` lint is unstable
|
||||||
|
= help: add `#![feature(multiple_supertrait_upcastable)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
warning: 6 warnings emitted
|
||||||
|
|
|
@ -4,7 +4,7 @@ warning: unused return value of `Box::<T>::from_raw` that must be used
|
||||||
LL | Box::from_raw(ptr);
|
LL | Box::from_raw(ptr);
|
||||||
| ^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: call `drop(from_raw(ptr))` if you intend to drop the `Box`
|
= note: call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/must-use-box-from-raw.rs:5:9
|
--> $DIR/must-use-box-from-raw.rs:5:9
|
||||||
|
|
|
|
||||||
|
|
3
src/test/ui/match/single-line.rs
Normal file
3
src/test/ui/match/single-line.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
let _ = match Some(42) { Some(x) => x, None => "" }; //~ ERROR E0308
|
||||||
|
}
|
12
src/test/ui/match/single-line.stderr
Normal file
12
src/test/ui/match/single-line.stderr
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/single-line.rs:2:52
|
||||||
|
|
|
||||||
|
LL | let _ = match Some(42) { Some(x) => x, None => "" };
|
||||||
|
| -------------- - ^^ expected integer, found `&str`
|
||||||
|
| | |
|
||||||
|
| | this is found to be of type `{integer}`
|
||||||
|
| `match` arms have incompatible types
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
10
src/test/ui/repr/transparent-enum-too-many-variants.rs
Normal file
10
src/test/ui/repr/transparent-enum-too-many-variants.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
use std::mem::size_of;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
enum Foo { //~ ERROR E0731
|
||||||
|
A(u8), B(u8),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Foo: {}", size_of::<Foo>());
|
||||||
|
}
|
11
src/test/ui/repr/transparent-enum-too-many-variants.stderr
Normal file
11
src/test/ui/repr/transparent-enum-too-many-variants.stderr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
error[E0731]: transparent enum needs exactly one variant, but has 2
|
||||||
|
--> $DIR/transparent-enum-too-many-variants.rs:4:1
|
||||||
|
|
|
||||||
|
LL | enum Foo {
|
||||||
|
| ^^^^^^^^ needs exactly one variant, but has 2
|
||||||
|
LL | A(u8), B(u8),
|
||||||
|
| - - too many variants in `Foo`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0731`.
|
|
@ -0,0 +1,10 @@
|
||||||
|
#![feature(multiple_supertrait_upcastable)]
|
||||||
|
#![deny(multiple_supertrait_upcastable)]
|
||||||
|
|
||||||
|
trait A {}
|
||||||
|
trait B {}
|
||||||
|
|
||||||
|
trait C: A + B {}
|
||||||
|
//~^ ERROR `C` is object-safe and has multiple supertraits
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,14 @@
|
||||||
|
error: `C` is object-safe and has multiple supertraits
|
||||||
|
--> $DIR/multiple_supertrait_upcastable.rs:7:1
|
||||||
|
|
|
||||||
|
LL | trait C: A + B {}
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/multiple_supertrait_upcastable.rs:2:9
|
||||||
|
|
|
||||||
|
LL | #![deny(multiple_supertrait_upcastable)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Reference in a new issue