Auto merge of #111089 - Dylan-DPC:rollup-b8oj6du, r=Dylan-DPC

Rollup of 7 pull requests

Successful merges:

 - #105076 (Refactor core::char::EscapeDefault and co. structures)
 - #108161 (Add `ConstParamTy` trait)
 - #108668 (Stabilize debugger_visualizer)
 - #110512 (Fix elaboration with associated type bounds)
 - #110895 (Remove `all` in target_thread_local cfg)
 - #110955 (uplift `clippy::clone_double_ref` as `suspicious_double_ref_op`)
 - #111048 (Mark`feature(return_position_impl_trait_in_trait)` and`feature(async_fn_in_trait)` as not incomplete)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-05-02 06:36:44 +00:00
commit 7b99493492
134 changed files with 1702 additions and 1156 deletions

View file

@ -40,7 +40,6 @@
use tempfile::Builder as TempFileBuilder;
use itertools::Itertools;
use std::borrow::Borrow;
use std::cell::OnceCell;
use std::collections::BTreeSet;
use std::ffi::OsString;
@ -576,17 +575,17 @@ struct ThorinSession<Relocations> {
impl<Relocations> ThorinSession<Relocations> {
fn alloc_mmap(&self, data: Mmap) -> &Mmap {
(*self.arena_mmap.alloc(data)).borrow()
&*self.arena_mmap.alloc(data)
}
}
impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
fn alloc_data(&self, data: Vec<u8>) -> &[u8] {
(*self.arena_data.alloc(data)).borrow()
&*self.arena_data.alloc(data)
}
fn alloc_relocation(&self, data: Relocations) -> &Relocations {
(*self.arena_relocations.alloc(data)).borrow()
&*self.arena_relocations.alloc(data)
}
fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {

View file

@ -130,6 +130,8 @@ macro_rules! declare_features {
(accepted, copy_closures, "1.26.0", Some(44490), None),
/// Allows `crate` in paths.
(accepted, crate_in_paths, "1.30.0", Some(45477), None),
/// Allows using `#[debugger_visualizer]` attribute.
(accepted, debugger_visualizer, "CURRENT_RUSTC_VERSION", Some(95939), None),
/// Allows rustc to inject a default alloc_error_handler
(accepted, default_alloc_error_handler, "1.68.0", Some(66741), None),
/// Allows using assigning a default type to type parameters in algebraic data type definitions.

View file

@ -310,7 +310,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
/// Allows async functions to be declared, implemented, and used in traits.
(incomplete, async_fn_in_trait, "1.66.0", Some(91611), None),
(active, async_fn_in_trait, "1.66.0", Some(91611), None),
/// Treat `extern "C"` function as nounwind.
(active, c_unwind, "1.52.0", Some(74990), None),
/// Allows using C-variadics.
@ -363,8 +363,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
(active, custom_test_frameworks, "1.30.0", Some(50297), None),
/// Allows using `#[debugger_visualizer]`.
(active, debugger_visualizer, "1.62.0", Some(95939), None),
/// Allows declarative macros 2.0 (`macro`).
(active, decl_macro, "1.17.0", Some(39412), None),
/// Allows default type parameters to influence type inference.
@ -496,7 +494,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
/// Allows `repr(simd)` and importing the various simd intrinsics.
(active, repr_simd, "1.4.0", Some(27731), None),
/// Allows return-position `impl Trait` in traits.
(incomplete, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None),
(active, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None),
/// Allows bounding the return type of AFIT/RPITIT.
(incomplete, return_type_notation, "1.70.0", Some(109417), None),
/// Allows `extern "rust-cold"`.

View file

@ -403,16 +403,16 @@ pub struct BuiltinAttribute {
doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
),
// Debugging
ungated!(
debugger_visualizer, Normal,
template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), DuplicatesOk
),
// ==========================================================================
// Unstable attributes:
// ==========================================================================
// RFC #3191: #[debugger_visualizer] support
gated!(
debugger_visualizer, Normal, template!(List: r#"natvis_file = "...", gdb_script_file = "...""#),
DuplicatesOk, experimental!(debugger_visualizer)
),
// Linking:
gated!(
naked, Normal, template!(Word), WarnFollowing, @only_local: true,

View file

@ -293,6 +293,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None;
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;

View file

@ -35,6 +35,10 @@ hir_analysis_field_already_declared =
hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
hir_analysis_const_param_ty_impl_on_non_adt =
the trait `ConstParamTy` may not be implemented for this type
.label = type is not a structure or enumeration
hir_analysis_ambiguous_lifetime_bound =
ambiguous lifetime bound, explicit lifetime bound required

View file

@ -56,6 +56,9 @@
#[derive(Debug)]
pub struct PathSeg(pub DefId, pub usize);
#[derive(Copy, Clone, Debug)]
pub struct OnlySelfBounds(pub bool);
pub trait AstConv<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx>;
@ -670,6 +673,7 @@ fn instantiate_poly_trait_ref_inner(
args: &GenericArgs<'_>,
infer_args: bool,
self_ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
let (substs, arg_count) = self.create_substs_for_ast_path(
trait_ref_span,
@ -706,6 +710,7 @@ fn instantiate_poly_trait_ref_inner(
&mut dup_bindings,
binding_span.unwrap_or(binding.span),
constness,
only_self_bounds,
);
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
}
@ -741,6 +746,7 @@ pub(crate) fn instantiate_poly_trait_ref(
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
let hir_id = trait_ref.hir_ref_id;
let binding_span = None;
@ -766,6 +772,7 @@ pub(crate) fn instantiate_poly_trait_ref(
args,
infer_args,
self_ty,
only_self_bounds,
)
}
@ -777,6 +784,7 @@ pub(crate) fn instantiate_lang_item_trait_ref(
args: &GenericArgs<'_>,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
only_self_bounds: OnlySelfBounds,
) {
let binding_span = Some(span);
let constness = ty::BoundConstness::NotConst;
@ -799,6 +807,7 @@ pub(crate) fn instantiate_lang_item_trait_ref(
args,
infer_args,
self_ty,
only_self_bounds,
);
}
@ -947,6 +956,7 @@ pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>
ast_bounds: I,
bounds: &mut Bounds<'tcx>,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
only_self_bounds: OnlySelfBounds,
) {
for ast_bound in ast_bounds {
match ast_bound {
@ -964,11 +974,18 @@ pub(crate) fn add_bounds<'hir, I: Iterator<Item = &'hir hir::GenericBound<'hir>>
param_ty,
bounds,
false,
only_self_bounds,
);
}
&hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
self.instantiate_lang_item_trait_ref(
lang_item, span, hir_id, args, param_ty, bounds,
lang_item,
span,
hir_id,
args,
param_ty,
bounds,
only_self_bounds,
);
}
hir::GenericBound::Outlives(lifetime) => {
@ -1006,8 +1023,19 @@ pub(crate) fn compute_bounds(
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
only_self_bounds: OnlySelfBounds,
) -> Bounds<'tcx> {
self.compute_bounds_inner(param_ty, ast_bounds)
let mut bounds = Bounds::default();
self.add_bounds(
param_ty,
ast_bounds.iter(),
&mut bounds,
ty::List::empty(),
only_self_bounds,
);
debug!(?bounds);
bounds
}
/// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
@ -1029,17 +1057,14 @@ pub(crate) fn compute_bounds_that_match_assoc_type(
}
}
self.compute_bounds_inner(param_ty, &result)
}
fn compute_bounds_inner(
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
self.add_bounds(
param_ty,
result.iter(),
&mut bounds,
ty::List::empty(),
OnlySelfBounds(true),
);
debug!(?bounds);
bounds
@ -1062,6 +1087,7 @@ fn add_predicates_for_ast_type_binding(
dup_bindings: &mut FxHashMap<DefId, Span>,
path_span: Span,
constness: ty::BoundConstness,
only_self_bounds: OnlySelfBounds,
) -> Result<(), ErrorGuaranteed> {
// Given something like `U: SomeTrait<T = X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
@ -1361,8 +1387,20 @@ fn add_predicates_for_ast_type_binding(
//
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
self.add_bounds(param_ty, ast_bounds.iter(), bounds, projection_ty.bound_vars());
//
// NOTE: If `only_self_bounds` is true, do NOT expand this associated
// type bound into a trait predicate, since we only want to add predicates
// for the `Self` type.
if !only_self_bounds.0 {
let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
self.add_bounds(
param_ty,
ast_bounds.iter(),
bounds,
projection_ty.bound_vars(),
only_self_bounds,
);
}
}
}
Ok(())
@ -1403,6 +1441,10 @@ fn conv_object_ty_poly_trait_ref(
dummy_self,
&mut bounds,
false,
// FIXME: This should be `true`, but we don't really handle
// associated type bounds or type aliases in objects in a way
// that makes this meaningful, I think.
OnlySelfBounds(false),
) {
potential_assoc_types.extend(cur_potential_assoc_types);
}

View file

@ -1,9 +1,11 @@
//! Check properties that are required by built-in traits and set
//! up data structures required by type-checking/codegen.
use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
use crate::errors::{
ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, MultiSpan};
use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
@ -14,9 +16,11 @@
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::misc::{
type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
};
use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause};
@ -27,6 +31,7 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
Checker { tcx, trait_def_id }
.check(lang_items.drop_trait(), visit_implementation_of_drop)
.check(lang_items.copy_trait(), visit_implementation_of_copy)
.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
}
@ -83,110 +88,7 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
Ok(()) => {}
Err(CopyImplementationError::InfringingFields(fields)) => {
let mut err = struct_span_err!(
tcx.sess,
span,
E0204,
"the trait `Copy` cannot be implemented for this type"
);
// We'll try to suggest constraining type parameters to fulfill the requirements of
// their `Copy` implementation.
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
let mut bounds = vec![];
let mut seen_tys = FxHashSet::default();
for (field, ty, reason) in fields {
// Only report an error once per type.
if !seen_tys.insert(ty) {
continue;
}
let field_span = tcx.def_span(field.did);
err.span_label(field_span, "this field does not implement `Copy`");
match reason {
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
for error in fulfillment_errors {
let error_predicate = error.obligation.predicate;
// Only note if it's not the root obligation, otherwise it's trivial and
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
// FIXME: This error could be more descriptive, especially if the error_predicate
// contains a foreign type or if it's a deeply nested type...
if error_predicate != error.root_obligation.predicate {
errors
.entry((ty.to_string(), error_predicate.to_string()))
.or_default()
.push(error.obligation.cause.span);
}
if let ty::PredicateKind::Clause(ty::Clause::Trait(
ty::TraitPredicate {
trait_ref,
polarity: ty::ImplPolarity::Positive,
..
},
)) = error_predicate.kind().skip_binder()
{
let ty = trait_ref.self_ty();
if let ty::Param(_) = ty.kind() {
bounds.push((
format!("{ty}"),
trait_ref.print_only_trait_path().to_string(),
Some(trait_ref.def_id),
));
}
}
}
}
InfringingFieldsReason::Regions(region_errors) => {
for error in region_errors {
let ty = ty.to_string();
match error {
RegionResolutionError::ConcreteFailure(origin, a, b) => {
let predicate = format!("{b}: {a}");
errors
.entry((ty.clone(), predicate.clone()))
.or_default()
.push(origin.span());
if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
bounds.push((b.to_string(), a.to_string(), None));
}
}
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
let predicate = format!("{a}: {b}");
errors
.entry((ty.clone(), predicate.clone()))
.or_default()
.push(origin.span());
if let infer::region_constraints::GenericKind::Param(_) = a {
bounds.push((a.to_string(), b.to_string(), None));
}
}
_ => continue,
}
}
}
}
}
for ((ty, error_predicate), spans) in errors {
let span: MultiSpan = spans.into();
err.span_note(
span,
&format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
);
}
suggest_constraining_type_params(
tcx,
tcx.hir().get_generics(impl_did).expect("impls always have generics"),
&mut err,
bounds.iter().map(|(param, constraint, def_id)| {
(param.as_str(), constraint.as_str(), *def_id)
}),
None,
);
err.emit();
infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
}
Err(CopyImplementationError::NotAnAdt) => {
tcx.sess.emit_err(CopyImplOnNonAdt { span });
@ -197,6 +99,29 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
}
}
fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
let self_type = tcx.type_of(impl_did).subst_identity();
assert!(!self_type.has_escaping_bound_vars());
let param_env = tcx.param_env(impl_did);
let span = match tcx.hir().expect_item(impl_did).expect_impl() {
hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
impl_ => impl_.self_ty.span,
};
let cause = traits::ObligationCause::misc(span, impl_did);
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
Ok(()) => {}
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
}
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
}
}
}
fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
@ -593,3 +518,119 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
CoerceUnsizedInfo { custom_kind: kind }
}
fn infringing_fields_error(
tcx: TyCtxt<'_>,
fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
lang_item: LangItem,
impl_did: LocalDefId,
impl_span: Span,
) -> ErrorGuaranteed {
let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
let trait_name = tcx.def_path_str(trait_did);
let mut err = struct_span_err!(
tcx.sess,
impl_span,
E0204,
"the trait `{trait_name}` cannot be implemented for this type"
);
// We'll try to suggest constraining type parameters to fulfill the requirements of
// their `Copy` implementation.
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
let mut bounds = vec![];
let mut seen_tys = FxHashSet::default();
for (field, ty, reason) in fields {
// Only report an error once per type.
if !seen_tys.insert(ty) {
continue;
}
let field_span = tcx.def_span(field.did);
err.span_label(field_span, format!("this field does not implement `{trait_name}`"));
match reason {
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
for error in fulfillment_errors {
let error_predicate = error.obligation.predicate;
// Only note if it's not the root obligation, otherwise it's trivial and
// should be self-explanatory (i.e. a field literally doesn't implement Copy).
// FIXME: This error could be more descriptive, especially if the error_predicate
// contains a foreign type or if it's a deeply nested type...
if error_predicate != error.root_obligation.predicate {
errors
.entry((ty.to_string(), error_predicate.to_string()))
.or_default()
.push(error.obligation.cause.span);
}
if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
trait_ref,
polarity: ty::ImplPolarity::Positive,
..
})) = error_predicate.kind().skip_binder()
{
let ty = trait_ref.self_ty();
if let ty::Param(_) = ty.kind() {
bounds.push((
format!("{ty}"),
trait_ref.print_only_trait_path().to_string(),
Some(trait_ref.def_id),
));
}
}
}
}
InfringingFieldsReason::Regions(region_errors) => {
for error in region_errors {
let ty = ty.to_string();
match error {
RegionResolutionError::ConcreteFailure(origin, a, b) => {
let predicate = format!("{b}: {a}");
errors
.entry((ty.clone(), predicate.clone()))
.or_default()
.push(origin.span());
if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
bounds.push((b.to_string(), a.to_string(), None));
}
}
RegionResolutionError::GenericBoundFailure(origin, a, b) => {
let predicate = format!("{a}: {b}");
errors
.entry((ty.clone(), predicate.clone()))
.or_default()
.push(origin.span());
if let infer::region_constraints::GenericKind::Param(_) = a {
bounds.push((a.to_string(), b.to_string(), None));
}
}
_ => continue,
}
}
}
}
}
for ((ty, error_predicate), spans) in errors {
let span: MultiSpan = spans.into();
err.span_note(
span,
format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
);
}
suggest_constraining_type_params(
tcx,
tcx.hir().get_generics(impl_did).expect("impls always have generics"),
&mut err,
bounds
.iter()
.map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
None,
);
err.emit()
}

View file

@ -1,5 +1,5 @@
use super::ItemCtxt;
use crate::astconv::AstConv;
use crate::astconv::{AstConv, OnlySelfBounds};
use rustc_hir as hir;
use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts;
@ -26,7 +26,7 @@ fn associated_type_bounds<'tcx>(
);
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
// Associated types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
@ -67,7 +67,7 @@ fn opaque_type_bounds<'tcx>(
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
ty::print::with_no_queries!({
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
// Opaque types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
debug!(?bounds);

View file

@ -1,4 +1,4 @@
use crate::astconv::AstConv;
use crate::astconv::{AstConv, OnlySelfBounds};
use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
@ -14,9 +14,6 @@
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
#[derive(Debug)]
struct OnlySelfBounds(bool);
/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
/// `Self: Trait` predicates for traits.
@ -99,8 +96,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
| ItemKind::Struct(_, generics)
| ItemKind::Union(_, generics) => generics,
ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => {
is_trait = Some(ty::TraitRef::identity(tcx, def_id.to_def_id()));
ItemKind::Trait(_, _, generics, self_bounds, ..)
| ItemKind::TraitAlias(generics, self_bounds) => {
is_trait = Some(self_bounds);
generics
}
ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics,
@ -122,10 +120,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// Below we'll consider the bounds on the type parameters (including `Self`)
// and the explicit where-clauses, but to get the full set of predicates
// on a trait we need to add in the supertrait bounds and bounds found on
// associated types.
if let Some(_trait_ref) = is_trait {
predicates.extend(tcx.implied_predicates_of(def_id).predicates.iter().cloned());
// on a trait we must also consider the bounds that follow the trait's name,
// like `trait Foo: A + B + C`.
if let Some(self_bounds) = is_trait {
predicates.extend(
icx.astconv()
.compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
.predicates(),
);
}
// In default impls, we can assume that the self type implements
@ -225,7 +227,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
let mut bounds = Bounds::default();
icx.astconv().add_bounds(ty, bound_pred.bounds.iter(), &mut bounds, bound_vars);
icx.astconv().add_bounds(
ty,
bound_pred.bounds.iter(),
&mut bounds,
bound_vars,
OnlySelfBounds(false),
);
predicates.extend(bounds.predicates());
}
@ -608,7 +616,7 @@ pub(super) fn implied_predicates_with_filter(
let (superbounds, where_bounds_that_match) = match filter {
PredicateFilter::All => (
// Convert the bounds that follow the colon (or equal in trait aliases)
icx.astconv().compute_bounds(self_param_ty, bounds),
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)),
// Also include all where clause bounds
icx.type_parameter_bounds_in_generics(
generics,
@ -620,7 +628,7 @@ pub(super) fn implied_predicates_with_filter(
),
PredicateFilter::SelfOnly => (
// Convert the bounds that follow the colon (or equal in trait aliases)
icx.astconv().compute_bounds(self_param_ty, bounds),
icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)),
// Include where clause bounds for `Self`
icx.type_parameter_bounds_in_generics(
generics,
@ -774,32 +782,35 @@ fn type_parameter_bounds_in_generics(
only_self_bounds: OnlySelfBounds,
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
ast_generics
.predicates
.iter()
.filter_map(|wp| match wp {
hir::WherePredicate::BoundPredicate(bp) => Some(bp),
_ => None,
})
.flat_map(|bp| {
let bt = if bp.is_param_bound(param_def_id.to_def_id()) {
Some(ty)
} else if !only_self_bounds.0 {
Some(self.to_ty(bp.bounded_ty))
} else {
None
};
let bvars = self.tcx.late_bound_vars(bp.hir_id);
let mut bounds = Bounds::default();
bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
|(_, b, _)| match assoc_name {
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
},
)
})
.flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
.collect()
for predicate in ast_generics.predicates {
let hir::WherePredicate::BoundPredicate(predicate) = predicate else {
continue;
};
let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
ty
} else if !only_self_bounds.0 {
self.to_ty(predicate.bounded_ty)
} else {
continue;
};
let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
self.astconv().add_bounds(
bound_ty,
predicate.bounds.iter().filter(|bound| {
assoc_name
.map_or(true, |assoc_name| self.bound_defines_assoc_item(bound, assoc_name))
}),
&mut bounds,
bound_vars,
only_self_bounds,
);
}
bounds.predicates().collect()
}
#[instrument(level = "trace", skip(self))]
@ -817,19 +828,3 @@ fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident)
}
}
}
/// Converts a specific `GenericBound` from the AST into a set of
/// predicates that apply to the self type. A vector is returned
/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
/// and `<T as Bar>::X == i32`).
fn predicates_from_bound<'tcx>(
astconv: &dyn AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &'tcx hir::GenericBound<'tcx>,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let mut bounds = Bounds::default();
astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
bounds.predicates().collect()
}

View file

@ -107,6 +107,14 @@ pub struct CopyImplOnNonAdt {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
pub struct ConstParamTyImplOnNonAdt {
#[primary_span]
#[label]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
pub struct TraitObjectDeclaredWithNoTraits {

View file

@ -116,7 +116,7 @@
use std::ops::Not;
use astconv::AstConv;
use astconv::{AstConv, OnlySelfBounds};
use bounds::Bounds;
fluent_messages! { "../messages.ftl" }
@ -531,6 +531,7 @@ pub fn hir_trait_to_predicates<'tcx>(
self_ty,
&mut bounds,
true,
OnlySelfBounds(false),
);
bounds

View file

@ -50,6 +50,14 @@ lint_deprecated_lint_name =
lint_renamed_or_removed_lint = {$msg}
.suggestion = use the new name
lint_suspicious_double_ref_op =
using `.{$call}()` on a double reference, which returns `{$ty}` instead of {$op ->
*[should_not_happen] [{$op}]
[deref] dereferencing
[borrow] borrowing
[clone] cloning
} the inner type
lint_unknown_lint =
unknown lint: `{$name}`
.suggestion = did you mean

View file

@ -1150,6 +1150,14 @@ pub struct NoopMethodCallDiag<'a> {
pub label: Span,
}
#[derive(LintDiagnostic)]
#[diag(lint_suspicious_double_ref_op)]
pub struct SuspiciousDoubleRefDiag<'a> {
pub call: Symbol,
pub ty: Ty<'a>,
pub op: &'static str,
}
// pass_by_value.rs
#[derive(LintDiagnostic)]
#[diag(lint_pass_by_value)]

View file

@ -1,10 +1,11 @@
use crate::context::LintContext;
use crate::lints::NoopMethodCallDiag;
use crate::lints::{NoopMethodCallDiag, SuspiciousDoubleRefDiag};
use crate::LateContext;
use crate::LateLintPass;
use rustc_hir::def::DefKind;
use rustc_hir::{Expr, ExprKind};
use rustc_middle::ty;
use rustc_middle::ty::adjustment::Adjust;
use rustc_span::symbol::sym;
declare_lint! {
@ -35,14 +36,44 @@
"detects the use of well-known noop methods"
}
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
declare_lint! {
/// The `suspicious_double_ref_op` lint checks for usage of `.clone()`/`.borrow()`/`.deref()`
/// on an `&&T` when `T: !Deref/Borrow/Clone`, which means the call will return the inner `&T`,
/// instead of performing the operation on the underlying `T` and can be confusing.
///
/// ### Example
///
/// ```rust
/// # #![allow(unused)]
/// struct Foo;
/// let foo = &&Foo;
/// let clone: &Foo = foo.clone();
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Since `Foo` doesn't implement `Clone`, running `.clone()` only dereferences the double
/// reference, instead of cloning the inner type which should be what was intended.
pub SUSPICIOUS_DOUBLE_REF_OP,
Warn,
"suspicious call of trait method on `&&T`"
}
declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL, SUSPICIOUS_DOUBLE_REF_OP]);
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls.
let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
return
let ExprKind::MethodCall(call, receiver, _, call_span) = &expr.kind else {
return;
};
if call_span.from_expansion() {
return;
}
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
// traits and ignore any other method call.
let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
@ -70,25 +101,39 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
};
// (Re)check that it implements the noop diagnostic.
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
if !matches!(
name,
sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
) {
return;
}
let op = match name {
sym::noop_method_borrow => "borrow",
sym::noop_method_clone => "clone",
sym::noop_method_deref => "deref",
_ => return,
};
let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
if receiver_ty != expr_ty {
// This lint will only trigger if the receiver type and resulting expression \
// type are the same, implying that the method call is unnecessary.
let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
// If there is any user defined auto-deref step, then we don't want to warn.
// https://github.com/rust-lang/rust-clippy/issues/9272
if arg_adjustments.iter().any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) {
return;
}
let expr_span = expr.span;
let span = expr_span.with_lo(receiver.span.hi());
cx.emit_spanned_lint(
NOOP_METHOD_CALL,
span,
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
);
if receiver_ty == expr_ty {
cx.emit_spanned_lint(
NOOP_METHOD_CALL,
span,
NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
);
} else {
cx.emit_spanned_lint(
SUSPICIOUS_DOUBLE_REF_OP,
span,
SuspiciousDoubleRefDiag { call: call.ident.name, ty: expr_ty, op },
)
}
}
}

View file

@ -531,6 +531,7 @@
const_mut_refs,
const_panic,
const_panic_fmt,
const_param_ty,
const_precise_live_drops,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,

View file

@ -2,13 +2,14 @@
use crate::traits::{self, ObligationCause, ObligationCtxt};
use hir::LangItem;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{self, AdtDef, GenericArg, List, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use super::outlives_bounds::InferCtxtExt;
@ -19,6 +20,11 @@ pub enum CopyImplementationError<'tcx> {
HasDestructor,
}
pub enum ConstParamTyImplementationError<'tcx> {
InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
NotAnAdtOrBuiltinAllowed,
}
pub enum InfringingFieldsReason<'tcx> {
Fulfill(Vec<FulfillmentError<'tcx>>),
Regions(Vec<RegionResolutionError<'tcx>>),
@ -27,7 +33,10 @@ pub enum InfringingFieldsReason<'tcx> {
/// Checks that the fields of the type (an ADT) all implement copy.
///
/// If fields don't implement copy, return an error containing a list of
/// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`.
/// those violating fields.
///
/// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`,
/// a reference or an array returns `Err(NotAnAdt)`.
pub fn type_allowed_to_implement_copy<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@ -47,12 +56,82 @@ pub fn type_allowed_to_implement_copy<'tcx>(
| ty::Ref(_, _, hir::Mutability::Not)
| ty::Array(..) => return Ok(()),
ty::Adt(adt, substs) => (adt, substs),
&ty::Adt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt),
};
let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
all_fields_implement_trait(
tcx,
param_env,
self_type,
adt,
substs,
parent_cause,
hir::LangItem::Copy,
)
.map_err(CopyImplementationError::InfringingFields)?;
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
Ok(())
}
/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`.
///
/// If fields don't implement `ConstParamTy`, return an error containing a list of
/// those violating fields.
///
/// If it's not an ADT, int ty, `bool` or `char`, returns `Err(NotAnAdtOrBuiltinAllowed)`.
pub fn type_allowed_to_implement_const_param_ty<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
self_type: Ty<'tcx>,
parent_cause: ObligationCause<'tcx>,
) -> Result<(), ConstParamTyImplementationError<'tcx>> {
let (adt, substs) = match self_type.kind() {
// `core` provides these impls.
ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Char
| ty::Str
| ty::Array(..)
| ty::Slice(_)
| ty::Ref(.., hir::Mutability::Not) => return Ok(()),
&ty::Adt(adt, substs) => (adt, substs),
_ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
};
all_fields_implement_trait(
tcx,
param_env,
self_type,
adt,
substs,
parent_cause,
hir::LangItem::ConstParamTy,
)
.map_err(ConstParamTyImplementationError::InfrigingFields)?;
Ok(())
}
/// Check that all fields of a given `adt` implement `lang_item` trait.
pub fn all_fields_implement_trait<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
self_type: Ty<'tcx>,
adt: AdtDef<'tcx>,
substs: &'tcx List<GenericArg<'tcx>>,
parent_cause: ObligationCause<'tcx>,
lang_item: LangItem,
) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span));
let mut infringing = Vec::new();
for variant in adt.variants() {
@ -93,7 +172,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
// between expected and found const-generic types. Don't report an
// additional copy error here, since it's not typically useful.
if !normalization_errors.is_empty() || ty.references_error() {
tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
continue;
}
@ -101,7 +180,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
ObligationCause::dummy_with_span(field_ty_span),
param_env,
ty,
copy_def_id,
trait_def_id,
);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
@ -124,15 +203,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
}
}
if !infringing.is_empty() {
return Err(CopyImplementationError::InfringingFields(infringing));
}
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
Ok(())
if infringing.is_empty() { Ok(()) } else { Err(infringing) }
}
pub fn check_tys_might_be_eq<'tcx>(

View file

@ -9,10 +9,10 @@
#![stable(feature = "core_ascii", since = "1.26.0")]
use crate::escape;
use crate::fmt;
use crate::iter::FusedIterator;
use crate::ops::Range;
use crate::str::from_utf8_unchecked;
use crate::num::NonZeroUsize;
/// An iterator over the escaped version of a byte.
///
@ -21,10 +21,7 @@
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct EscapeDefault {
range: Range<u8>,
data: [u8; 4],
}
pub struct EscapeDefault(escape::EscapeIterInner<4>);
/// Returns an iterator that produces an escaped version of a `u8`.
///
@ -90,21 +87,9 @@ pub struct EscapeDefault {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn escape_default(c: u8) -> EscapeDefault {
let (data, len) = match c {
b'\t' => ([b'\\', b't', 0, 0], 2),
b'\r' => ([b'\\', b'r', 0, 0], 2),
b'\n' => ([b'\\', b'n', 0, 0], 2),
b'\\' => ([b'\\', b'\\', 0, 0], 2),
b'\'' => ([b'\\', b'\'', 0, 0], 2),
b'"' => ([b'\\', b'"', 0, 0], 2),
b'\x20'..=b'\x7e' => ([c, 0, 0, 0], 1),
_ => {
let hex_digits: &[u8; 16] = b"0123456789abcdef";
([b'\\', b'x', hex_digits[(c >> 4) as usize], hex_digits[(c & 0xf) as usize]], 4)
}
};
return EscapeDefault { range: 0..len, data };
let mut data = [0; 4];
let range = escape::escape_ascii_into(&mut data, c);
EscapeDefault(escape::EscapeIterInner::new(data, range))
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -113,33 +98,59 @@ impl Iterator for EscapeDefault {
#[inline]
fn next(&mut self) -> Option<u8> {
self.range.next().map(|i| self.data[i as usize])
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
let n = self.0.len();
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
self.0.len()
}
#[inline]
fn last(mut self) -> Option<u8> {
self.next_back()
self.0.next_back()
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.0.advance_by(n)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl DoubleEndedIterator for EscapeDefault {
#[inline]
fn next_back(&mut self) -> Option<u8> {
self.range.next_back().map(|i| self.data[i as usize])
self.0.next_back()
}
#[inline]
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.0.advance_back_by(n)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExactSizeIterator for EscapeDefault {}
impl ExactSizeIterator for EscapeDefault {
#[inline]
fn len(&self) -> usize {
self.0.len()
}
}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDefault {}
#[stable(feature = "ascii_escape_display", since = "1.39.0")]
impl fmt::Display for EscapeDefault {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// SAFETY: ok because `escape_default` created only valid utf-8 data
f.write_str(unsafe {
from_utf8_unchecked(&self.data[(self.range.start as usize)..(self.range.end as usize)])
})
f.write_str(self.0.as_str())
}
}

View file

@ -380,20 +380,7 @@ pub const fn to_digit(self, radix: u32) -> Option<u32> {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn escape_unicode(self) -> EscapeUnicode {
let c = self as u32;
// or-ing 1 ensures that for c==0 the code computes that one
// digit should be printed and (which is the same) avoids the
// (31 - 32) underflow
let msb = 31 - (c | 1).leading_zeros();
// the index of the most significant hex digit
let ms_hex_digit = msb / 4;
EscapeUnicode {
c: self,
state: EscapeUnicodeState::Backslash,
hex_digit_idx: ms_hex_digit as usize,
}
EscapeUnicode::new(self)
}
/// An extended version of `escape_debug` that optionally permits escaping
@ -403,21 +390,20 @@ pub fn escape_unicode(self) -> EscapeUnicode {
/// characters, and double quotes in strings.
#[inline]
pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug {
let init_state = match self {
'\0' => EscapeDefaultState::Backslash('0'),
'\t' => EscapeDefaultState::Backslash('t'),
'\r' => EscapeDefaultState::Backslash('r'),
'\n' => EscapeDefaultState::Backslash('n'),
'\\' => EscapeDefaultState::Backslash(self),
'"' if args.escape_double_quote => EscapeDefaultState::Backslash(self),
'\'' if args.escape_single_quote => EscapeDefaultState::Backslash(self),
match self {
'\0' => EscapeDebug::backslash(b'0'),
'\t' => EscapeDebug::backslash(b't'),
'\r' => EscapeDebug::backslash(b'r'),
'\n' => EscapeDebug::backslash(b'n'),
'\\' => EscapeDebug::backslash(b'\\'),
'"' if args.escape_double_quote => EscapeDebug::backslash(b'"'),
'\'' if args.escape_single_quote => EscapeDebug::backslash(b'\''),
_ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
EscapeDefaultState::Unicode(self.escape_unicode())
EscapeDebug::from_unicode(self.escape_unicode())
}
_ if is_printable(self) => EscapeDefaultState::Char(self),
_ => EscapeDefaultState::Unicode(self.escape_unicode()),
};
EscapeDebug(EscapeDefault { state: init_state })
_ if is_printable(self) => EscapeDebug::printable(self),
_ => EscapeDebug::from_unicode(self.escape_unicode()),
}
}
/// Returns an iterator that yields the literal escape code of a character
@ -515,15 +501,14 @@ pub fn escape_debug(self) -> EscapeDebug {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn escape_default(self) -> EscapeDefault {
let init_state = match self {
'\t' => EscapeDefaultState::Backslash('t'),
'\r' => EscapeDefaultState::Backslash('r'),
'\n' => EscapeDefaultState::Backslash('n'),
'\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
'\x20'..='\x7e' => EscapeDefaultState::Char(self),
_ => EscapeDefaultState::Unicode(self.escape_unicode()),
};
EscapeDefault { state: init_state }
match self {
'\t' => EscapeDefault::backslash(b't'),
'\r' => EscapeDefault::backslash(b'r'),
'\n' => EscapeDefault::backslash(b'n'),
'\\' | '\'' | '"' => EscapeDefault::backslash(self as u8),
'\x20'..='\x7e' => EscapeDefault::printable(self as u8),
_ => EscapeDefault::from_unicode(self.escape_unicode()),
}
}
/// Returns the number of bytes this `char` would need if encoded in UTF-8.

View file

@ -39,8 +39,10 @@
pub use self::methods::encode_utf8_raw;
use crate::error::Error;
use crate::escape;
use crate::fmt::{self, Write};
use crate::iter::FusedIterator;
use crate::num::NonZeroUsize;
pub(crate) use self::methods::EscapeDebugExtArgs;
@ -146,86 +148,44 @@ pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
/// [`escape_unicode`]: char::escape_unicode
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct EscapeUnicode {
c: char,
state: EscapeUnicodeState,
pub struct EscapeUnicode(escape::EscapeIterInner<10>);
// The index of the next hex digit to be printed (0 if none),
// i.e., the number of remaining hex digits to be printed;
// increasing from the least significant digit: 0x543210
hex_digit_idx: usize,
}
// The enum values are ordered so that their representation is the
// same as the remaining length (besides the hexadecimal digits). This
// likely makes `len()` a single load from memory) and inline-worth.
#[derive(Clone, Debug)]
enum EscapeUnicodeState {
Done,
RightBrace,
Value,
LeftBrace,
Type,
Backslash,
impl EscapeUnicode {
fn new(chr: char) -> Self {
let mut data = [0; 10];
let range = escape::escape_unicode_into(&mut data, chr);
Self(escape::EscapeIterInner::new(data, range))
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeUnicode {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> {
match self.state {
EscapeUnicodeState::Backslash => {
self.state = EscapeUnicodeState::Type;
Some('\\')
}
EscapeUnicodeState::Type => {
self.state = EscapeUnicodeState::LeftBrace;
Some('u')
}
EscapeUnicodeState::LeftBrace => {
self.state = EscapeUnicodeState::Value;
Some('{')
}
EscapeUnicodeState::Value => {
let hex_digit = ((self.c as u32) >> (self.hex_digit_idx * 4)) & 0xf;
let c = char::from_digit(hex_digit, 16).unwrap();
if self.hex_digit_idx == 0 {
self.state = EscapeUnicodeState::RightBrace;
} else {
self.hex_digit_idx -= 1;
}
Some(c)
}
EscapeUnicodeState::RightBrace => {
self.state = EscapeUnicodeState::Done;
Some('}')
}
EscapeUnicodeState::Done => None,
}
self.0.next().map(char::from)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len();
let n = self.0.len();
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
self.len()
self.0.len()
}
fn last(self) -> Option<char> {
match self.state {
EscapeUnicodeState::Done => None,
#[inline]
fn last(mut self) -> Option<char> {
self.0.next_back().map(char::from)
}
EscapeUnicodeState::RightBrace
| EscapeUnicodeState::Value
| EscapeUnicodeState::LeftBrace
| EscapeUnicodeState::Type
| EscapeUnicodeState::Backslash => Some('}'),
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.0.advance_by(n)
}
}
@ -233,16 +193,7 @@ fn last(self) -> Option<char> {
impl ExactSizeIterator for EscapeUnicode {
#[inline]
fn len(&self) -> usize {
// The match is a single memory access with no branching
self.hex_digit_idx
+ match self.state {
EscapeUnicodeState::Done => 0,
EscapeUnicodeState::RightBrace => 1,
EscapeUnicodeState::Value => 2,
EscapeUnicodeState::LeftBrace => 3,
EscapeUnicodeState::Type => 4,
EscapeUnicodeState::Backslash => 5,
}
self.0.len()
}
}
@ -252,10 +203,7 @@ impl FusedIterator for EscapeUnicode {}
#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for EscapeUnicode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for c in self.clone() {
f.write_char(c)?;
}
Ok(())
f.write_str(self.0.as_str())
}
}
@ -267,90 +215,60 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// [`escape_default`]: char::escape_default
#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct EscapeDefault {
state: EscapeDefaultState,
}
pub struct EscapeDefault(escape::EscapeIterInner<10>);
#[derive(Clone, Debug)]
enum EscapeDefaultState {
Done,
Char(char),
Backslash(char),
Unicode(EscapeUnicode),
impl EscapeDefault {
fn printable(chr: u8) -> Self {
let data = [chr, 0, 0, 0, 0, 0, 0, 0, 0, 0];
Self(escape::EscapeIterInner::new(data, 0..1))
}
fn backslash(chr: u8) -> Self {
let data = [b'\\', chr, 0, 0, 0, 0, 0, 0, 0, 0];
Self(escape::EscapeIterInner::new(data, 0..2))
}
fn from_unicode(esc: EscapeUnicode) -> Self {
Self(esc.0)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for EscapeDefault {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> {
match self.state {
EscapeDefaultState::Backslash(c) => {
self.state = EscapeDefaultState::Char(c);
Some('\\')
}
EscapeDefaultState::Char(c) => {
self.state = EscapeDefaultState::Done;
Some(c)
}
EscapeDefaultState::Done => None,
EscapeDefaultState::Unicode(ref mut iter) => iter.next(),
}
self.0.next().map(char::from)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len();
let n = self.0.len();
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
self.len()
self.0.len()
}
fn nth(&mut self, n: usize) -> Option<char> {
match self.state {
EscapeDefaultState::Backslash(c) if n == 0 => {
self.state = EscapeDefaultState::Char(c);
Some('\\')
}
EscapeDefaultState::Backslash(c) if n == 1 => {
self.state = EscapeDefaultState::Done;
Some(c)
}
EscapeDefaultState::Backslash(_) => {
self.state = EscapeDefaultState::Done;
None
}
EscapeDefaultState::Char(c) => {
self.state = EscapeDefaultState::Done;
if n == 0 { Some(c) } else { None }
}
EscapeDefaultState::Done => None,
EscapeDefaultState::Unicode(ref mut i) => i.nth(n),
}
#[inline]
fn last(mut self) -> Option<char> {
self.0.next_back().map(char::from)
}
fn last(self) -> Option<char> {
match self.state {
EscapeDefaultState::Unicode(iter) => iter.last(),
EscapeDefaultState::Done => None,
EscapeDefaultState::Backslash(c) | EscapeDefaultState::Char(c) => Some(c),
}
#[inline]
fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.0.advance_by(n)
}
}
#[stable(feature = "exact_size_escape", since = "1.11.0")]
impl ExactSizeIterator for EscapeDefault {
#[inline]
fn len(&self) -> usize {
match self.state {
EscapeDefaultState::Done => 0,
EscapeDefaultState::Char(_) => 1,
EscapeDefaultState::Backslash(_) => 2,
EscapeDefaultState::Unicode(ref iter) => iter.len(),
}
self.0.len()
}
}
@ -360,10 +278,7 @@ impl FusedIterator for EscapeDefault {}
#[stable(feature = "char_struct_display", since = "1.16.0")]
impl fmt::Display for EscapeDefault {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for c in self.clone() {
f.write_char(c)?;
}
Ok(())
f.write_str(self.0.as_str())
}
}
@ -375,21 +290,74 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// [`escape_debug`]: char::escape_debug
#[stable(feature = "char_escape_debug", since = "1.20.0")]
#[derive(Clone, Debug)]
pub struct EscapeDebug(EscapeDefault);
pub struct EscapeDebug(EscapeDebugInner);
#[stable(feature = "char_escape_debug", since = "1.20.0")]
impl Iterator for EscapeDebug {
type Item = char;
fn next(&mut self) -> Option<char> {
self.0.next()
#[derive(Clone, Debug)]
// Note: Its possible to manually encode the EscapeDebugInner inside of
// EscapeIterInner (e.g. with alive=254..255 indicating that data[0..4] holds
// a char) which would likely result in a more optimised code. For now we use
// the option easier to implement.
enum EscapeDebugInner {
Bytes(escape::EscapeIterInner<10>),
Char(char),
}
impl EscapeDebug {
fn printable(chr: char) -> Self {
Self(EscapeDebugInner::Char(chr))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
fn backslash(chr: u8) -> Self {
let data = [b'\\', chr, 0, 0, 0, 0, 0, 0, 0, 0];
let iter = escape::EscapeIterInner::new(data, 0..2);
Self(EscapeDebugInner::Bytes(iter))
}
fn from_unicode(esc: EscapeUnicode) -> Self {
Self(EscapeDebugInner::Bytes(esc.0))
}
fn clear(&mut self) {
let bytes = escape::EscapeIterInner::new([0; 10], 0..0);
self.0 = EscapeDebugInner::Bytes(bytes);
}
}
#[stable(feature = "char_escape_debug", since = "1.20.0")]
impl ExactSizeIterator for EscapeDebug {}
impl Iterator for EscapeDebug {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> {
match self.0 {
EscapeDebugInner::Bytes(ref mut bytes) => bytes.next().map(char::from),
EscapeDebugInner::Char(chr) => {
self.clear();
Some(chr)
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.len();
(n, Some(n))
}
#[inline]
fn count(self) -> usize {
self.len()
}
}
#[stable(feature = "char_escape_debug", since = "1.20.0")]
impl ExactSizeIterator for EscapeDebug {
fn len(&self) -> usize {
match &self.0 {
EscapeDebugInner::Bytes(bytes) => bytes.len(),
EscapeDebugInner::Char(_) => 1,
}
}
}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for EscapeDebug {}
@ -397,7 +365,10 @@ impl FusedIterator for EscapeDebug {}
#[stable(feature = "char_escape_debug", since = "1.20.0")]
impl fmt::Display for EscapeDebug {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
match &self.0 {
EscapeDebugInner::Bytes(bytes) => f.write_str(bytes.as_str()),
EscapeDebugInner::Char(chr) => f.write_char(*chr),
}
}
}

View file

@ -0,0 +1,99 @@
//! Helper code for character escaping.
use crate::num::NonZeroUsize;
use crate::ops::Range;
const HEX_DIGITS: [u8; 16] = *b"0123456789abcdef";
/// Escapes a byte into provided buffer; returns length of escaped
/// representation.
pub(crate) fn escape_ascii_into(output: &mut [u8; 4], byte: u8) -> Range<u8> {
let (data, len) = match byte {
b'\t' => ([b'\\', b't', 0, 0], 2),
b'\r' => ([b'\\', b'r', 0, 0], 2),
b'\n' => ([b'\\', b'n', 0, 0], 2),
b'\\' => ([b'\\', b'\\', 0, 0], 2),
b'\'' => ([b'\\', b'\'', 0, 0], 2),
b'"' => ([b'\\', b'"', 0, 0], 2),
b'\x20'..=b'\x7e' => ([byte, 0, 0, 0], 1),
_ => {
let hi = HEX_DIGITS[usize::from(byte >> 4)];
let lo = HEX_DIGITS[usize::from(byte & 0xf)];
([b'\\', b'x', hi, lo], 4)
}
};
*output = data;
0..(len as u8)
}
/// Escapes a character into provided buffer using `\u{NNNN}` representation.
pub(crate) fn escape_unicode_into(output: &mut [u8; 10], ch: char) -> Range<u8> {
output[9] = b'}';
let ch = ch as u32;
output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize];
output[4] = HEX_DIGITS[((ch >> 16) & 15) as usize];
output[5] = HEX_DIGITS[((ch >> 12) & 15) as usize];
output[6] = HEX_DIGITS[((ch >> 8) & 15) as usize];
output[7] = HEX_DIGITS[((ch >> 4) & 15) as usize];
output[8] = HEX_DIGITS[((ch >> 0) & 15) as usize];
// or-ing 1 ensures that for ch==0 the code computes that one digit should
// be printed.
let start = (ch | 1).leading_zeros() as usize / 4 - 2;
output[start..start + 3].copy_from_slice(b"\\u{");
(start as u8)..10
}
/// An iterator over an fixed-size array.
///
/// This is essentially equivalent to arrays IntoIter except that indexes are
/// limited to u8 to reduce size of the structure.
#[derive(Clone, Debug)]
pub(crate) struct EscapeIterInner<const N: usize> {
// Invariant: data[alive] is all ASCII.
pub(crate) data: [u8; N],
// Invariant: alive.start <= alive.end <= N.
pub(crate) alive: Range<u8>,
}
impl<const N: usize> EscapeIterInner<N> {
pub fn new(data: [u8; N], alive: Range<u8>) -> Self {
const { assert!(N < 256) };
debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}");
let this = Self { data, alive };
debug_assert!(this.as_bytes().is_ascii(), "Expected ASCII, got {:?}", this.as_bytes());
this
}
fn as_bytes(&self) -> &[u8] {
&self.data[usize::from(self.alive.start)..usize::from(self.alive.end)]
}
pub fn as_str(&self) -> &str {
// SAFETY: self.data[self.alive] is all ASCII characters.
unsafe { crate::str::from_utf8_unchecked(self.as_bytes()) }
}
pub fn len(&self) -> usize {
usize::from(self.alive.end - self.alive.start)
}
pub fn next(&mut self) -> Option<u8> {
self.alive.next().map(|i| self.data[usize::from(i)])
}
pub fn next_back(&mut self) -> Option<u8> {
self.alive.next_back().map(|i| self.data[usize::from(i)])
}
pub fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.alive.advance_by(n)
}
pub fn advance_back_by(&mut self, n: usize) -> Result<(), NonZeroUsize> {
self.alive.advance_back_by(n)
}
}

View file

@ -162,6 +162,7 @@
#![feature(const_waker)]
#![feature(core_panic)]
#![feature(duration_consts_float)]
#![feature(internal_impls_macro)]
#![feature(ip)]
#![feature(is_ascii_octdigit)]
#![feature(maybe_uninit_uninit_array)]
@ -376,6 +377,7 @@ pub mod assert_matches {
// note: does not need to be public
mod bool;
mod escape;
mod tuple;
mod unit;

View file

@ -12,6 +12,60 @@
use crate::hash::Hash;
use crate::hash::Hasher;
/// Implements a given marker trait for multiple types at the same time.
///
/// The basic syntax looks like this:
/// ```ignore private macro
/// marker_impls! { MarkerTrait for u8, i8 }
/// ```
/// You can also implement `unsafe` traits
/// ```ignore private macro
/// marker_impls! { unsafe MarkerTrait for u8, i8 }
/// ```
/// Add attributes to all impls:
/// ```ignore private macro
/// marker_impls! {
/// #[allow(lint)]
/// #[unstable(feature = "marker_trait", issue = "none")]
/// MarkerTrait for u8, i8
/// }
/// ```
/// And use generics:
/// ```ignore private macro
/// marker_impls! {
/// MarkerTrait for
/// u8, i8,
/// {T: ?Sized} *const T,
/// {T: ?Sized} *mut T,
/// {T: MarkerTrait} PhantomData<T>,
/// u32,
/// }
/// ```
#[unstable(feature = "internal_impls_macro", issue = "none")]
macro marker_impls {
( $(#[$($meta:tt)*])* $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => {
// This inner macro is needed because... idk macros are weird.
// It allows repeating `meta` on all impls.
#[unstable(feature = "internal_impls_macro", issue = "none")]
macro _impl {
( $$({$$($$bounds_:tt)*})? $$T_:ty ) => {
$(#[$($meta)*])* impl<$$($$($$bounds_)*)?> $Trait for $$T_ {}
}
}
$( _impl! { $({$($bounds)*})? $T } )+
},
( $(#[$($meta:tt)*])* unsafe $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => {
#[unstable(feature = "internal_impls_macro", issue = "none")]
macro _impl {
( $$({$$($$bounds_:tt)*})? $$T_:ty ) => {
$(#[$($meta)*])* unsafe impl<$$($$($$bounds_)*)?> $Trait for $$T_ {}
}
}
$( _impl! { $({$($bounds)*})? $T } )+
},
}
/// Types that can be transferred across thread boundaries.
///
/// This trait is automatically implemented when the compiler determines it's
@ -214,6 +268,20 @@ pub trait StructuralEq {
// Empty.
}
// FIXME: Remove special cases of these types from the compiler pattern checking code and always check `T: StructuralEq` instead
marker_impls! {
#[unstable(feature = "structural_match", issue = "31434")]
StructuralEq for
usize, u8, u16, u32, u64, u128,
isize, i8, i16, i32, i64, i128,
bool,
char,
str /* Technically requires `[u8]: StructuralEq` */,
{T, const N: usize} [T; N],
{T} [T],
{T: ?Sized} &T,
}
/// Types whose values can be duplicated simply by copying bits.
///
/// By default, variable bindings have 'move semantics.' In other
@ -401,6 +469,30 @@ pub trait Copy: Clone {
/* compiler built-in */
}
// Implementations of `Copy` for primitive types.
//
// Implementations that cannot be described in Rust
// are implemented in `traits::SelectionContext::copy_clone_conditions()`
// in `rustc_trait_selection`.
marker_impls! {
#[stable(feature = "rust1", since = "1.0.0")]
Copy for
usize, u8, u16, u32, u64, u128,
isize, i8, i16, i32, i64, i128,
f32, f64,
bool, char,
{T: ?Sized} *const T,
{T: ?Sized} *mut T,
}
#[unstable(feature = "never_type", issue = "35121")]
impl Copy for ! {}
/// Shared references can be copied, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for &T {}
/// Types for which it is safe to share references between threads.
///
/// This trait is automatically implemented when the compiler determines
@ -778,11 +870,14 @@ pub trait DiscriminantKind {
pub(crate) unsafe auto trait Freeze {}
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
unsafe impl<T: ?Sized> Freeze for *const T {}
unsafe impl<T: ?Sized> Freeze for *mut T {}
unsafe impl<T: ?Sized> Freeze for &T {}
unsafe impl<T: ?Sized> Freeze for &mut T {}
marker_impls! {
unsafe Freeze for
{T: ?Sized} PhantomData<T>,
{T: ?Sized} *const T,
{T: ?Sized} *mut T,
{T: ?Sized} &T,
{T: ?Sized} &mut T,
}
/// Types that can be safely moved after being pinned.
///
@ -843,17 +938,19 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
#[stable(feature = "pin", since = "1.33.0")]
impl !Unpin for PhantomPinned {}
#[stable(feature = "pin", since = "1.33.0")]
impl<'a, T: ?Sized + 'a> Unpin for &'a T {}
marker_impls! {
#[stable(feature = "pin", since = "1.33.0")]
Unpin for
{T: ?Sized} &T,
{T: ?Sized} &mut T,
}
#[stable(feature = "pin", since = "1.33.0")]
impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {}
#[stable(feature = "pin_raw", since = "1.38.0")]
impl<T: ?Sized> Unpin for *const T {}
#[stable(feature = "pin_raw", since = "1.38.0")]
impl<T: ?Sized> Unpin for *mut T {}
marker_impls! {
#[stable(feature = "pin_raw", since = "1.38.0")]
Unpin for
{T: ?Sized} *const T,
{T: ?Sized} *mut T,
}
/// A marker for types that can be dropped.
///
@ -888,43 +985,25 @@ pub trait Tuple {}
)]
pub trait PointerLike {}
/// Implementations of `Copy` for primitive types.
///
/// Implementations that cannot be described in Rust
/// are implemented in `traits::SelectionContext::copy_clone_conditions()`
/// in `rustc_trait_selection`.
mod copy_impls {
/// A marker for types which can be used as types of `const` generic parameters.
#[cfg_attr(not(bootstrap), lang = "const_param_ty")]
#[unstable(feature = "adt_const_params", issue = "95174")]
#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
pub trait ConstParamTy: StructuralEq {}
use super::Copy;
macro_rules! impl_copy {
($($t:ty)*) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Copy for $t {}
)*
}
}
impl_copy! {
usize u8 u16 u32 u64 u128
isize i8 i16 i32 i64 i128
f32 f64
bool char
}
#[unstable(feature = "never_type", issue = "35121")]
impl Copy for ! {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for *mut T {}
/// Shared references can be copied, but mutable references *cannot*!
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for &T {}
// FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure`
// FIXME(generic_const_parameter_types): handle `ty::Tuple`
marker_impls! {
#[unstable(feature = "adt_const_params", issue = "95174")]
ConstParamTy for
usize, u8, u16, u32, u64, u128,
isize, i8, i16, i32, i64, i128,
bool,
char,
str /* Technically requires `[u8]: ConstParamTy` */,
{T: ConstParamTy, const N: usize} [T; N],
{T: ConstParamTy} [T],
{T: ?Sized + ConstParamTy} &T,
}
/// A common trait implemented by all function pointers.

View file

@ -1,4 +1,5 @@
#[test]
#[cfg_attr(not(bootstrap), allow(suspicious_double_ref_op))]
fn test_borrowed_clone() {
let x = 5;
let y: &i32 = &x;

View file

@ -6,7 +6,7 @@
mod static_local;
#[doc(hidden)]
pub use static_local::{Key, thread_local_inner};
} else if #[cfg(all(target_thread_local))] {
} else if #[cfg(target_thread_local)] {
#[doc(hidden)]
mod fast_local;
#[doc(hidden)]

View file

@ -1,27 +0,0 @@
# `debugger_visualizer`
The tracking issue for this feature is: [#95939]
[#95939]: https://github.com/rust-lang/rust/issues/95939
------------------------
The `debugger_visualizer` attribute can be used to instruct the compiler
to embed a debugger visualizer file into the PDB/ELF generated by `rustc`.
## Examples
``` rust,ignore (partial-example)
#![feature(debugger_visualizer)]
#![debugger_visualizer(natvis_file = "foo.natvis")]
#![debugger_visualizer(gdb_script_file = "foo.py")]
struct Foo {
}
```
## Limitations
Currently, this feature only supports embedding Natvis files on `-windows-msvc`
targets via the `natvis_file` meta item. `-windows-gnu` targets are not currently
supported.

View file

@ -167,7 +167,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
display_fn(move |f| {
let mut bounds_dup = FxHashSet::default();
for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(b.clone())).enumerate() {
for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(*b)).enumerate() {
if i > 0 {
f.write_str(" + ")?;
}

View file

@ -313,7 +313,6 @@
crate::methods::CHARS_NEXT_CMP_INFO,
crate::methods::CLEAR_WITH_DRAIN_INFO,
crate::methods::CLONED_INSTEAD_OF_COPIED_INFO,
crate::methods::CLONE_DOUBLE_REF_INFO,
crate::methods::CLONE_ON_COPY_INFO,
crate::methods::CLONE_ON_REF_PTR_INFO,
crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::get_parent_node;
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg;
use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
@ -9,7 +8,6 @@
use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths};
use rustc_span::symbol::{sym, Symbol};
use super::CLONE_DOUBLE_REF;
use super::CLONE_ON_COPY;
/// Checks for the `CLONE_ON_COPY` lint.
@ -42,41 +40,7 @@ pub(super) fn check(
let ty = cx.typeck_results().expr_ty(expr);
if let ty::Ref(_, inner, _) = arg_ty.kind() {
if let ty::Ref(_, innermost, _) = inner.kind() {
span_lint_and_then(
cx,
CLONE_DOUBLE_REF,
expr.span,
&with_forced_trimmed_paths!(format!(
"using `clone` on a double-reference; \
this will copy the reference of type `{ty}` instead of cloning the inner type"
)),
|diag| {
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
let mut ty = innermost;
let mut n = 0;
while let ty::Ref(_, inner, _) = ty.kind() {
ty = inner;
n += 1;
}
let refs = "&".repeat(n + 1);
let derefs = "*".repeat(n);
let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})"));
diag.span_suggestion(
expr.span,
"try dereferencing it",
with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())),
Applicability::MaybeIncorrect,
);
diag.span_suggestion(
expr.span,
"or try being explicit if you are sure, that you want to clone a reference",
explicit,
Applicability::MaybeIncorrect,
);
}
},
);
if let ty::Ref(..) = inner.kind() {
return; // don't report clone_on_copy
}
}

View file

@ -984,29 +984,6 @@
"using 'clone' on a ref-counted pointer"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `.clone()` on an `&&T`.
///
/// ### Why is this bad?
/// Cloning an `&&T` copies the inner `&T`, instead of
/// cloning the underlying `T`.
///
/// ### Example
/// ```rust
/// fn main() {
/// let x = vec![1];
/// let y = &&x;
/// let z = y.clone();
/// println!("{:p} {:p}", *y, z); // prints out the same pointer
/// }
/// ```
#[clippy::version = "pre 1.29.0"]
pub CLONE_DOUBLE_REF,
correctness,
"using `clone` on `&&T`"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for usage of `.to_string()` on an `&&T` where
@ -3258,7 +3235,6 @@ pub fn new(
CHARS_LAST_CMP,
CLONE_ON_COPY,
CLONE_ON_REF_PTR,
CLONE_DOUBLE_REF,
COLLAPSIBLE_STR_REPLACE,
ITER_OVEREAGER_CLONED,
CLONED_INSTEAD_OF_COPIED,

View file

@ -30,6 +30,7 @@
("clippy::stutter", "clippy::module_name_repetitions"),
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
("clippy::zero_width_space", "clippy::invisible_characters"),
("clippy::clone_double_ref", "suspicious_double_ref_op"),
("clippy::drop_bounds", "drop_bounds"),
("clippy::for_loop_over_option", "for_loops_over_fallibles"),
("clippy::for_loop_over_result", "for_loops_over_fallibles"),

View file

@ -3,7 +3,7 @@
#![allow(unused_variables)]
#![allow(
clippy::borrow_deref_ref,
clippy::clone_double_ref,
suspicious_double_ref_op,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::uninlined_format_args

View file

@ -3,7 +3,7 @@
#![allow(unused_variables)]
#![allow(
clippy::borrow_deref_ref,
clippy::clone_double_ref,
suspicious_double_ref_op,
clippy::explicit_auto_deref,
clippy::needless_borrow,
clippy::uninlined_format_args

View file

@ -36,6 +36,7 @@
#![allow(enum_intrinsics_non_enums)]
#![allow(non_fmt_panics)]
#![allow(named_arguments_used_positionally)]
#![allow(suspicious_double_ref_op)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
@ -67,6 +68,7 @@
#![warn(clippy::module_name_repetitions)]
#![warn(clippy::recursive_format_impl)]
#![warn(clippy::invisible_characters)]
#![warn(suspicious_double_ref_op)]
#![warn(drop_bounds)]
#![warn(for_loops_over_fallibles)]
#![warn(for_loops_over_fallibles)]

View file

@ -36,6 +36,7 @@
#![allow(enum_intrinsics_non_enums)]
#![allow(non_fmt_panics)]
#![allow(named_arguments_used_positionally)]
#![allow(suspicious_double_ref_op)]
#![allow(temporary_cstring_as_ptr)]
#![allow(unknown_lints)]
#![allow(unused_labels)]
@ -67,6 +68,7 @@
#![warn(clippy::stutter)]
#![warn(clippy::to_string_in_display)]
#![warn(clippy::zero_width_space)]
#![warn(clippy::clone_double_ref)]
#![warn(clippy::drop_bounds)]
#![warn(clippy::for_loop_over_option)]
#![warn(clippy::for_loop_over_result)]

View file

@ -1,5 +1,5 @@
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
--> $DIR/rename.rs:42:9
--> $DIR/rename.rs:43:9
|
LL | #![warn(clippy::almost_complete_letter_range)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@ -7,250 +7,256 @@ LL | #![warn(clippy::almost_complete_letter_range)]
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
--> $DIR/rename.rs:43:9
--> $DIR/rename.rs:44:9
|
LL | #![warn(clippy::blacklisted_name)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
--> $DIR/rename.rs:44:9
--> $DIR/rename.rs:45:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
--> $DIR/rename.rs:45:9
--> $DIR/rename.rs:46:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
--> $DIR/rename.rs:46:9
--> $DIR/rename.rs:47:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
--> $DIR/rename.rs:47:9
--> $DIR/rename.rs:48:9
|
LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
--> $DIR/rename.rs:48:9
--> $DIR/rename.rs:49:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
--> $DIR/rename.rs:49:9
--> $DIR/rename.rs:50:9
|
LL | #![warn(clippy::derive_hash_xor_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
--> $DIR/rename.rs:50:9
--> $DIR/rename.rs:51:9
|
LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
--> $DIR/rename.rs:51:9
--> $DIR/rename.rs:52:9
|
LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
--> $DIR/rename.rs:52:9
--> $DIR/rename.rs:53:9
|
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
--> $DIR/rename.rs:53:9
--> $DIR/rename.rs:54:9
|
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
--> $DIR/rename.rs:54:9
--> $DIR/rename.rs:55:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
--> $DIR/rename.rs:55:9
--> $DIR/rename.rs:56:9
|
LL | #![warn(clippy::logic_bug)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
--> $DIR/rename.rs:56:9
--> $DIR/rename.rs:57:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
--> $DIR/rename.rs:57:9
--> $DIR/rename.rs:58:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:58:9
--> $DIR/rename.rs:59:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:59:9
--> $DIR/rename.rs:60:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:60:9
--> $DIR/rename.rs:61:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:61:9
--> $DIR/rename.rs:62:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
--> $DIR/rename.rs:62:9
--> $DIR/rename.rs:63:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
--> $DIR/rename.rs:63:9
--> $DIR/rename.rs:64:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
--> $DIR/rename.rs:64:9
--> $DIR/rename.rs:65:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
--> $DIR/rename.rs:65:9
--> $DIR/rename.rs:66:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
--> $DIR/rename.rs:66:9
--> $DIR/rename.rs:67:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
--> $DIR/rename.rs:67:9
--> $DIR/rename.rs:68:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
--> $DIR/rename.rs:68:9
--> $DIR/rename.rs:69:9
|
LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
--> $DIR/rename.rs:69:9
--> $DIR/rename.rs:70:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
--> $DIR/rename.rs:71:9
|
LL | #![warn(clippy::clone_double_ref)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
--> $DIR/rename.rs:70:9
--> $DIR/rename.rs:72:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:71:9
--> $DIR/rename.rs:73:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:72:9
--> $DIR/rename.rs:74:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
--> $DIR/rename.rs:73:9
--> $DIR/rename.rs:75:9
|
LL | #![warn(clippy::for_loops_over_fallibles)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
--> $DIR/rename.rs:74:9
--> $DIR/rename.rs:76:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
--> $DIR/rename.rs:75:9
--> $DIR/rename.rs:77:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
--> $DIR/rename.rs:76:9
--> $DIR/rename.rs:78:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
--> $DIR/rename.rs:77:9
--> $DIR/rename.rs:79:9
|
LL | #![warn(clippy::let_underscore_drop)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
--> $DIR/rename.rs:78:9
--> $DIR/rename.rs:80:9
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
--> $DIR/rename.rs:79:9
--> $DIR/rename.rs:81:9
|
LL | #![warn(clippy::panic_params)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
--> $DIR/rename.rs:80:9
--> $DIR/rename.rs:82:9
|
LL | #![warn(clippy::positional_named_format_parameters)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
--> $DIR/rename.rs:81:9
--> $DIR/rename.rs:83:9
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
--> $DIR/rename.rs:82:9
--> $DIR/rename.rs:84:9
|
LL | #![warn(clippy::unknown_clippy_lints)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
error: lint `clippy::unused_label` has been renamed to `unused_labels`
--> $DIR/rename.rs:83:9
--> $DIR/rename.rs:85:9
|
LL | #![warn(clippy::unused_label)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
error: aborting due to 42 previous errors
error: aborting due to 43 previous errors

View file

@ -42,14 +42,6 @@ fn clone_on_copy_generic<T: Copy>(t: T) {
Some(t).clone();
}
fn clone_on_double_ref() {
let x = vec![1];
let y = &&x;
let z: &Vec<_> = y.clone();
println!("{:p} {:p}", *y, z);
}
mod many_derefs {
struct A;
struct B;
@ -84,11 +76,6 @@ fn go1() {
let _: E = a.clone();
let _: E = *****a;
}
fn check(mut encoded: &[u8]) {
let _ = &mut encoded.clone();
let _ = &encoded.clone();
}
}
mod issue2076 {

View file

@ -44,63 +44,17 @@ error: using `clone` on type `Option<T>` which implements the `Copy` trait
LL | Some(t).clone();
| ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
error: using `clone` on a double-reference; this will copy the reference of type `&Vec<i32>` instead of cloning the inner type
--> $DIR/unnecessary_clone.rs:48:22
|
LL | let z: &Vec<_> = y.clone();
| ^^^^^^^^^
|
= note: `#[deny(clippy::clone_double_ref)]` on by default
help: try dereferencing it
|
LL | let z: &Vec<_> = &(*y).clone();
| ~~~~~~~~~~~~~
help: or try being explicit if you are sure, that you want to clone a reference
|
LL | let z: &Vec<_> = <&Vec<i32>>::clone(y);
| ~~~~~~~~~~~~~~~~~~~~~
error: using `clone` on type `E` which implements the `Copy` trait
--> $DIR/unnecessary_clone.rs:84:20
--> $DIR/unnecessary_clone.rs:76:20
|
LL | let _: E = a.clone();
| ^^^^^^^^^ help: try dereferencing it: `*****a`
error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type
--> $DIR/unnecessary_clone.rs:89:22
|
LL | let _ = &mut encoded.clone();
| ^^^^^^^^^^^^^^^
|
help: try dereferencing it
|
LL | let _ = &mut &(*encoded).clone();
| ~~~~~~~~~~~~~~~~~~~
help: or try being explicit if you are sure, that you want to clone a reference
|
LL | let _ = &mut <&[u8]>::clone(encoded);
| ~~~~~~~~~~~~~~~~~~~~~~~
error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type
--> $DIR/unnecessary_clone.rs:90:18
|
LL | let _ = &encoded.clone();
| ^^^^^^^^^^^^^^^
|
help: try dereferencing it
|
LL | let _ = &&(*encoded).clone();
| ~~~~~~~~~~~~~~~~~~~
help: or try being explicit if you are sure, that you want to clone a reference
|
LL | let _ = &<&[u8]>::clone(encoded);
| ~~~~~~~~~~~~~~~~~~~~~~~
error: using `.clone()` on a ref-counted pointer
--> $DIR/unnecessary_clone.rs:108:14
--> $DIR/unnecessary_clone.rs:95:14
|
LL | Some(try_opt!(Some(rc)).clone())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::<u8>::clone(&try_opt!(Some(rc)))`
error: aborting due to 12 previous errors
error: aborting due to 9 previous errors

View file

@ -1385,7 +1385,9 @@ fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &
let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
let mut unexpected = Vec::new();
let mut found = vec![false; expected_errors.len()];
for actual_error in &actual_errors {
for mut actual_error in actual_errors {
actual_error.msg = self.normalize_output(&actual_error.msg, &[]);
let opt_index =
expected_errors.iter().enumerate().position(|(index, expected_error)| {
!found[index]
@ -1404,7 +1406,8 @@ fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &
None => {
// If the test is a known bug, don't require that the error is annotated
if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) {
if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note)
{
self.error(&format!(
"{}:{}: unexpected {}: '{}'",
file_name,

View file

@ -2,7 +2,6 @@
// ignore-lldb
// no-prefer-dynamic
#![feature(debugger_visualizer)]
#![debugger_visualizer(natvis_file = "dependency-with-embedded-visualizers.natvis")]
#![debugger_visualizer(gdb_script_file = "dependency-with-embedded-visualizers.py")]
#![crate_type = "rlib"]

View file

@ -60,7 +60,6 @@
// gdb-check:$4 = "Person A" is 10 years old.
#![allow(unused_variables)]
#![feature(debugger_visualizer)]
#![debugger_visualizer(natvis_file = "embedded-visualizer.natvis")]
#![debugger_visualizer(gdb_script_file = "embedded-visualizer.py")]

View file

@ -19,6 +19,8 @@ pub trait SVec: Index<
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
Output = <Index<<Self as SVec>::Item,
//~^ expected 1 lifetime argument
//~| expected 1 generic argument
@ -26,6 +28,8 @@ pub trait SVec: Index<
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
Output = <Self as SVec>::Item> as SVec>::Item,
//~^ expected 1 lifetime argument
//~| expected 1 generic argument
@ -34,11 +38,15 @@ pub trait SVec: Index<
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| expected 1 generic argument
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
//~| missing generics for associated type `SVec::Item`
> {
type Item<'a, T>;

View file

@ -5,7 +5,7 @@ LL | <Self as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -21,7 +21,7 @@ LL | <Self as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -31,13 +31,13 @@ LL | <Self as SVec>::Item<T>,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:22:37
--> $DIR/issue-105742.rs:24:37
|
LL | Output = <Index<<Self as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -47,13 +47,13 @@ LL | Output = <Index<<Self as SVec>::Item<'a>,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:22:37
--> $DIR/issue-105742.rs:24:37
|
LL | Output = <Index<<Self as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -63,13 +63,13 @@ LL | Output = <Index<<Self as SVec>::Item<T>,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:30
--> $DIR/issue-105742.rs:33:30
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -79,13 +79,13 @@ LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:30
--> $DIR/issue-105742.rs:33:30
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -95,13 +95,13 @@ LL | Output = <Self as SVec>::Item<T>> as SVec>::Item,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:46
--> $DIR/issue-105742.rs:33:46
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -111,13 +111,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:46
--> $DIR/issue-105742.rs:33:46
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -133,7 +133,7 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -149,7 +149,7 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) {
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -165,7 +165,7 @@ LL | <Self as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -181,7 +181,7 @@ LL | <Self as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -191,13 +191,13 @@ LL | <Self as SVec>::Item<T>,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:22:37
--> $DIR/issue-105742.rs:24:37
|
LL | Output = <Index<<Self as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -207,13 +207,13 @@ LL | Output = <Index<<Self as SVec>::Item<'a>,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:22:37
--> $DIR/issue-105742.rs:24:37
|
LL | Output = <Index<<Self as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -223,13 +223,13 @@ LL | Output = <Index<<Self as SVec>::Item<T>,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:30
--> $DIR/issue-105742.rs:33:30
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -239,13 +239,13 @@ LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:30
--> $DIR/issue-105742.rs:33:30
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -255,13 +255,13 @@ LL | Output = <Self as SVec>::Item<T>> as SVec>::Item,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:46
--> $DIR/issue-105742.rs:33:46
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -271,13 +271,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:29:46
--> $DIR/issue-105742.rs:33:46
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -317,13 +317,141 @@ LL | | > {
| |__^ ...because it uses `Self` as a type parameter
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:45:38
--> $DIR/issue-105742.rs:15:21
|
LL | <Self as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
help: add missing lifetime argument
|
LL | <Self as SVec>::Item<'a>,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:15:21
|
LL | <Self as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
help: add missing generic argument
|
LL | <Self as SVec>::Item<T>,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:24:37
|
LL | Output = <Index<<Self as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
help: add missing lifetime argument
|
LL | Output = <Index<<Self as SVec>::Item<'a>,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:24:37
|
LL | Output = <Index<<Self as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
help: add missing generic argument
|
LL | Output = <Index<<Self as SVec>::Item<T>,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:33:30
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
help: add missing lifetime argument
|
LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:33:30
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
help: add missing generic argument
|
LL | Output = <Self as SVec>::Item<T>> as SVec>::Item,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:33:46
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
help: add missing lifetime argument
|
LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>,
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:33:46
|
LL | Output = <Self as SVec>::Item> as SVec>::Item,
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
help: add missing generic argument
|
LL | Output = <Self as SVec>::Item> as SVec>::Item<T>,
| +++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:53:38
|
LL | fn len(&self) -> <Self as SVec>::Item;
| ^^^^ expected 1 lifetime argument
|
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ --
@ -333,13 +461,13 @@ LL | fn len(&self) -> <Self as SVec>::Item<'_>;
| ++++
error[E0107]: missing generics for associated type `SVec::Item`
--> $DIR/issue-105742.rs:45:38
--> $DIR/issue-105742.rs:53:38
|
LL | fn len(&self) -> <Self as SVec>::Item;
| ^^^^ expected 1 generic argument
|
note: associated type defined here, with 1 generic parameter: `T`
--> $DIR/issue-105742.rs:43:10
--> $DIR/issue-105742.rs:51:10
|
LL | type Item<'a, T>;
| ^^^^ -
@ -348,7 +476,7 @@ help: add missing generic argument
LL | fn len(&self) -> <Self as SVec>::Item<T>;
| +++
error: aborting due to 21 previous errors
error: aborting due to 29 previous errors
Some errors have detailed explanations: E0038, E0107.
For more information about an error, try `rustc --explain E0038`.

View file

@ -193,10 +193,13 @@ trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
trait TRS1: Iterator<Item: Copy, Item: Send> {}
//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
trait TRS2: Iterator<Item: Copy, Item: Copy> {}
//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
trait TRS3: Iterator<Item: 'static, Item: 'static> {}
//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
trait TRW1<T>
where
T: Iterator<Item: Copy, Item: Send>,

View file

@ -367,7 +367,15 @@ LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:196:34
--> $DIR/duplicate.rs:194:34
|
LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:197:34
|
LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
| ---------- ^^^^^^^^^^ re-bound here
@ -375,7 +383,15 @@ LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:198:37
--> $DIR/duplicate.rs:197:34
|
LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:200:37
|
LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
| ------------- ^^^^^^^^^^^^^ re-bound here
@ -383,7 +399,15 @@ LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:202:29
--> $DIR/duplicate.rs:200:37
|
LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
| ------------- ^^^^^^^^^^^^^ re-bound here
| |
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:205:29
|
LL | T: Iterator<Item: Copy, Item: Send>,
| ---------- ^^^^^^^^^^ re-bound here
@ -391,7 +415,7 @@ LL | T: Iterator<Item: Copy, Item: Send>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:208:29
--> $DIR/duplicate.rs:211:29
|
LL | T: Iterator<Item: Copy, Item: Copy>,
| ---------- ^^^^^^^^^^ re-bound here
@ -399,7 +423,7 @@ LL | T: Iterator<Item: Copy, Item: Copy>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:214:32
--> $DIR/duplicate.rs:217:32
|
LL | T: Iterator<Item: 'static, Item: 'static>,
| ------------- ^^^^^^^^^^^^^ re-bound here
@ -407,7 +431,7 @@ LL | T: Iterator<Item: 'static, Item: 'static>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:220:32
--> $DIR/duplicate.rs:223:32
|
LL | Self: Iterator<Item: Copy, Item: Send>,
| ---------- ^^^^^^^^^^ re-bound here
@ -415,7 +439,7 @@ LL | Self: Iterator<Item: Copy, Item: Send>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:220:32
--> $DIR/duplicate.rs:223:32
|
LL | Self: Iterator<Item: Copy, Item: Send>,
| ---------- ^^^^^^^^^^ re-bound here
@ -423,7 +447,7 @@ LL | Self: Iterator<Item: Copy, Item: Send>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:227:32
--> $DIR/duplicate.rs:230:32
|
LL | Self: Iterator<Item: Copy, Item: Copy>,
| ---------- ^^^^^^^^^^ re-bound here
@ -431,7 +455,7 @@ LL | Self: Iterator<Item: Copy, Item: Copy>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:227:32
--> $DIR/duplicate.rs:230:32
|
LL | Self: Iterator<Item: Copy, Item: Copy>,
| ---------- ^^^^^^^^^^ re-bound here
@ -439,7 +463,7 @@ LL | Self: Iterator<Item: Copy, Item: Copy>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:234:35
--> $DIR/duplicate.rs:237:35
|
LL | Self: Iterator<Item: 'static, Item: 'static>,
| ------------- ^^^^^^^^^^^^^ re-bound here
@ -447,7 +471,7 @@ LL | Self: Iterator<Item: 'static, Item: 'static>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:234:35
--> $DIR/duplicate.rs:237:35
|
LL | Self: Iterator<Item: 'static, Item: 'static>,
| ------------- ^^^^^^^^^^^^^ re-bound here
@ -455,7 +479,7 @@ LL | Self: Iterator<Item: 'static, Item: 'static>,
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:252:40
--> $DIR/duplicate.rs:255:40
|
LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
| ---------- ^^^^^^^^^^ re-bound here
@ -463,7 +487,7 @@ LL | type TADyn1 = dyn Iterator<Item: Copy, Item: Send>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:254:44
--> $DIR/duplicate.rs:257:44
|
LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
| ---------- ^^^^^^^^^^ re-bound here
@ -471,7 +495,7 @@ LL | type TADyn2 = Box<dyn Iterator<Item: Copy, Item: Copy>>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:256:43
--> $DIR/duplicate.rs:259:43
|
LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
| ------------- ^^^^^^^^^^^^^ re-bound here
@ -479,7 +503,7 @@ LL | type TADyn3 = dyn Iterator<Item: 'static, Item: 'static>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:240:34
--> $DIR/duplicate.rs:243:34
|
LL | type A: Iterator<Item: Copy, Item: Send>;
| ---------- ^^^^^^^^^^ re-bound here
@ -487,7 +511,7 @@ LL | type A: Iterator<Item: Copy, Item: Send>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:244:34
--> $DIR/duplicate.rs:247:34
|
LL | type A: Iterator<Item: Copy, Item: Copy>;
| ---------- ^^^^^^^^^^ re-bound here
@ -495,13 +519,13 @@ LL | type A: Iterator<Item: Copy, Item: Copy>;
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/duplicate.rs:248:37
--> $DIR/duplicate.rs:251:37
|
LL | type A: Iterator<Item: 'static, Item: 'static>;
| ------------- ^^^^^^^^^^^^^ re-bound here
| |
| `Item` bound here first
error: aborting due to 63 previous errors
error: aborting due to 66 previous errors
For more information about this error, try `rustc --explain E0719`.

View file

@ -2,7 +2,6 @@
#![feature(return_type_notation, async_fn_in_trait)]
//~^ WARN the feature `return_type_notation` is incomplete
//~| WARN the feature `async_fn_in_trait` is incomplete
trait Trait {
async fn method() {}

View file

@ -1,11 +1,11 @@
error: return type notation uses `()` instead of `(..)` for elided arguments
--> $DIR/bad-inputs-and-output.rs:19:24
--> $DIR/bad-inputs-and-output.rs:18:24
|
LL | fn baz<T: Trait<method(..): Send>>() {}
| ^^ help: remove the `..`
error[E0658]: associated type bounds are unstable
--> $DIR/bad-inputs-and-output.rs:11:17
--> $DIR/bad-inputs-and-output.rs:10:17
|
LL | fn foo<T: Trait<method(i32): Send>>() {}
| ^^^^^^^^^^^^^^^^^
@ -14,7 +14,7 @@ LL | fn foo<T: Trait<method(i32): Send>>() {}
= help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
error[E0658]: associated type bounds are unstable
--> $DIR/bad-inputs-and-output.rs:15:17
--> $DIR/bad-inputs-and-output.rs:14:17
|
LL | fn bar<T: Trait<method() -> (): Send>>() {}
| ^^^^^^^^^^^^^^^^^^^^
@ -31,26 +31,18 @@ LL | #![feature(return_type_notation, async_fn_in_trait)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/bad-inputs-and-output.rs:3:34
|
LL | #![feature(return_type_notation, async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
error: argument types not allowed with return type notation
--> $DIR/bad-inputs-and-output.rs:11:23
--> $DIR/bad-inputs-and-output.rs:10:23
|
LL | fn foo<T: Trait<method(i32): Send>>() {}
| ^^^^^ help: remove the input types: `()`
error: return type not allowed with return type notation
--> $DIR/bad-inputs-and-output.rs:15:25
--> $DIR/bad-inputs-and-output.rs:14:25
|
LL | fn bar<T: Trait<method() -> (): Send>>() {}
| ^^^^^^ help: remove the return type
error: aborting due to 5 previous errors; 2 warnings emitted
error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0658`.

View file

@ -4,7 +4,6 @@
#![feature(return_type_notation, async_fn_in_trait)]
//~^ WARN the feature `return_type_notation` is incomplete
//~| WARN the feature `async_fn_in_trait` is incomplete
trait Foo {
async fn method() -> Result<(), ()>;

View file

@ -7,13 +7,5 @@ LL | #![feature(return_type_notation, async_fn_in_trait)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/basic.rs:5:34
|
LL | #![feature(return_type_notation, async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
warning: 2 warnings emitted
warning: 1 warning emitted

View file

@ -7,31 +7,23 @@ LL | #![feature(return_type_notation, async_fn_in_trait)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/basic.rs:5:34
|
LL | #![feature(return_type_notation, async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
error: future cannot be sent between threads safely
--> $DIR/basic.rs:24:13
--> $DIR/basic.rs:23:13
|
LL | is_send(foo::<T>());
| ^^^^^^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>>`
note: future is not `Send` as it awaits another future which is not `Send`
--> $DIR/basic.rs:14:5
--> $DIR/basic.rs:13:5
|
LL | T::method().await?;
| ^^^^^^^^^^^ await occurs here on type `impl Future<Output = Result<(), ()>>`, which is not `Send`
note: required by a bound in `is_send`
--> $DIR/basic.rs:18:20
--> $DIR/basic.rs:17:20
|
LL | fn is_send(_: impl Send) {}
| ^^^^ required by this bound in `is_send`
error: aborting due to previous error; 2 warnings emitted
error: aborting due to previous error; 1 warning emitted

View file

@ -2,7 +2,6 @@
#![feature(return_type_notation, async_fn_in_trait)]
//~^ WARN the feature `return_type_notation` is incomplete
//~| WARN the feature `async_fn_in_trait` is incomplete
use std::future::Future;

View file

@ -7,19 +7,11 @@ LL | #![feature(return_type_notation, async_fn_in_trait)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/equality.rs:3:34
|
LL | #![feature(return_type_notation, async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
error: return type notation is not allowed to use type equality
--> $DIR/equality.rs:13:18
--> $DIR/equality.rs:12:18
|
LL | fn test<T: Trait<method() = Box<dyn Future<Output = ()>>>>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error; 2 warnings emitted
error: aborting due to previous error; 1 warning emitted

View file

@ -2,7 +2,6 @@
#![feature(return_type_notation, async_fn_in_trait)]
//~^ WARN the feature `return_type_notation` is incomplete
//~| WARN the feature `async_fn_in_trait` is incomplete
trait Trait {
async fn method() {}

View file

@ -7,19 +7,11 @@ LL | #![feature(return_type_notation, async_fn_in_trait)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/missing.rs:3:34
|
LL | #![feature(return_type_notation, async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
error: cannot find associated function `methid` in trait `Trait`
--> $DIR/missing.rs:11:17
--> $DIR/missing.rs:10:17
|
LL | fn bar<T: Trait<methid(): Send>>() {}
| ^^^^^^^^^^^^^^
error: aborting due to previous error; 2 warnings emitted
error: aborting due to previous error; 1 warning emitted

View file

@ -0,0 +1,26 @@
// check-pass
// Make sure that we don't look into associated type bounds when looking for
// supertraits that define an associated type. Fixes #76593.
#![feature(associated_type_bounds)]
trait Load: Sized {
type Blob;
}
trait Primitive: Load<Blob = Self> {}
trait BlobPtr: Primitive {}
trait CleanPtr: Load<Blob: BlobPtr> {
fn to_blob(&self) -> Self::Blob;
}
impl Load for () {
type Blob = Self;
}
impl Primitive for () {}
impl BlobPtr for () {}
fn main() {}

View file

@ -1,11 +0,0 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/async-default-fn-overridden.rs:6:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -1,11 +0,0 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/async-default-fn-overridden.rs:6:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: 1 warning emitted

View file

@ -4,7 +4,6 @@
// revisions: current next
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use
use std::future::Future;

View file

@ -1,11 +1,11 @@
error: expected identifier, found keyword `self`
--> $DIR/bad-signatures.rs:9:23
--> $DIR/bad-signatures.rs:8:23
|
LL | async fn bar(&abc self);
| ^^^^ expected identifier, found keyword
error: expected one of `:`, `@`, or `|`, found keyword `self`
--> $DIR/bad-signatures.rs:9:23
--> $DIR/bad-signatures.rs:8:23
|
LL | async fn bar(&abc self);
| -----^^^^
@ -13,14 +13,5 @@ LL | async fn bar(&abc self);
| | expected one of `:`, `@`, or `|`
| help: declare the type after the parameter binding: `<identifier>: <type>`
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/bad-signatures.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to 2 previous errors

View file

@ -1,11 +1,11 @@
error: expected identifier, found keyword `self`
--> $DIR/bad-signatures.rs:9:23
--> $DIR/bad-signatures.rs:8:23
|
LL | async fn bar(&abc self);
| ^^^^ expected identifier, found keyword
error: expected one of `:`, `@`, or `|`, found keyword `self`
--> $DIR/bad-signatures.rs:9:23
--> $DIR/bad-signatures.rs:8:23
|
LL | async fn bar(&abc self);
| -----^^^^
@ -13,14 +13,5 @@ LL | async fn bar(&abc self);
| | expected one of `:`, `@`, or `|`
| help: declare the type after the parameter binding: `<identifier>: <type>`
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/bad-signatures.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to 2 previous errors

View file

@ -3,7 +3,6 @@
// revisions: current next
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete
trait MyTrait {
async fn bar(&abc self);

View file

@ -1,12 +1,3 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/dont-project-to-specializable-projection.rs:6:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error: async associated function in trait cannot be specialized
--> $DIR/dont-project-to-specializable-projection.rs:16:5
|
@ -15,5 +6,5 @@ LL | default async fn foo(_: T) -> &'static str {
|
= note: specialization behaves in inconsistent and surprising ways with `#![feature(async_fn_in_trait)]`, and for now is disallowed
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error

View file

@ -1,12 +1,3 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/dont-project-to-specializable-projection.rs:6:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/dont-project-to-specializable-projection.rs:16:35
|
@ -29,6 +20,6 @@ LL | default async fn foo(_: T) -> &'static str {
|
= note: specialization behaves in inconsistent and surprising ways with `#![feature(async_fn_in_trait)]`, and for now is disallowed
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0053`.

View file

@ -1,14 +1,5 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/lifetime-mismatch.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
--> $DIR/lifetime-mismatch.rs:14:17
--> $DIR/lifetime-mismatch.rs:13:17
|
LL | async fn foo<'a>(&self);
| ---- lifetimes in impl do not match this method in trait
@ -16,6 +7,6 @@ LL | async fn foo<'a>(&self);
LL | async fn foo(&self) {}
| ^ lifetimes do not match method in trait
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error
For more information about this error, try `rustc --explain E0195`.

View file

@ -1,14 +1,5 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/lifetime-mismatch.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration
--> $DIR/lifetime-mismatch.rs:14:17
--> $DIR/lifetime-mismatch.rs:13:17
|
LL | async fn foo<'a>(&self);
| ---- lifetimes in impl do not match this method in trait
@ -16,6 +7,6 @@ LL | async fn foo<'a>(&self);
LL | async fn foo(&self) {}
| ^ lifetimes do not match method in trait
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error
For more information about this error, try `rustc --explain E0195`.

View file

@ -3,7 +3,6 @@
// revisions: current next
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
trait MyTrait {
async fn foo<'a>(&self);

View file

@ -1,29 +1,20 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/missing-send-bound.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error: future cannot be sent between threads safely
--> $DIR/missing-send-bound.rs:17:20
--> $DIR/missing-send-bound.rs:16:20
|
LL | assert_is_send(test::<T>());
| ^^^^^^^^^^^ future returned by `test` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
note: future is not `Send` as it awaits another future which is not `Send`
--> $DIR/missing-send-bound.rs:13:5
--> $DIR/missing-send-bound.rs:12:5
|
LL | T::bar().await;
| ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
note: required by a bound in `assert_is_send`
--> $DIR/missing-send-bound.rs:21:27
--> $DIR/missing-send-bound.rs:20:27
|
LL | fn assert_is_send(_: impl Send) {}
| ^^^^ required by this bound in `assert_is_send`
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error

View file

@ -1,29 +1,20 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/missing-send-bound.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error: future cannot be sent between threads safely
--> $DIR/missing-send-bound.rs:17:20
--> $DIR/missing-send-bound.rs:16:20
|
LL | assert_is_send(test::<T>());
| ^^^^^^^^^^^ future returned by `test` is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
note: future is not `Send` as it awaits another future which is not `Send`
--> $DIR/missing-send-bound.rs:13:5
--> $DIR/missing-send-bound.rs:12:5
|
LL | T::bar().await;
| ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send`
note: required by a bound in `assert_is_send`
--> $DIR/missing-send-bound.rs:21:27
--> $DIR/missing-send-bound.rs:20:27
|
LL | fn assert_is_send(_: impl Send) {}
| ^^^^ required by this bound in `assert_is_send`
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error

View file

@ -3,7 +3,6 @@
// revisions: current next
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
trait Foo {
async fn bar();

View file

@ -1,20 +1,11 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/object-safety.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/object-safety.rs:13:12
--> $DIR/object-safety.rs:12:12
|
LL | let x: &dyn Foo = todo!();
| ^^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety.rs:9:14
--> $DIR/object-safety.rs:8:14
|
LL | trait Foo {
| --- this trait cannot be made into an object...
@ -22,6 +13,6 @@ LL | async fn foo(&self);
| ^^^ ...because method `foo` is `async`
= help: consider moving `foo` to another trait
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error
For more information about this error, try `rustc --explain E0038`.

View file

@ -1,20 +1,11 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/object-safety.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0038]: the trait `Foo` cannot be made into an object
--> $DIR/object-safety.rs:13:12
--> $DIR/object-safety.rs:12:12
|
LL | let x: &dyn Foo = todo!();
| ^^^^^^^^ `Foo` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $DIR/object-safety.rs:9:14
--> $DIR/object-safety.rs:8:14
|
LL | trait Foo {
| --- this trait cannot be made into an object...
@ -22,6 +13,6 @@ LL | async fn foo(&self);
| ^^^ ...because method `foo` is `async`
= help: consider moving `foo` to another trait
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error
For more information about this error, try `rustc --explain E0038`.

View file

@ -3,7 +3,6 @@
// revisions: current next
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
trait Foo {
async fn foo(&self);

View file

@ -1,14 +1,5 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/return-type-suggestion.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/return-type-suggestion.rs:10:9
--> $DIR/return-type-suggestion.rs:9:9
|
LL | Ok(())
| ^^^^^^- help: consider using a semicolon here: `;`
@ -18,6 +9,6 @@ LL | Ok(())
= note: expected unit type `()`
found enum `Result<(), _>`
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -1,14 +1,5 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/return-type-suggestion.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0308]: mismatched types
--> $DIR/return-type-suggestion.rs:10:9
--> $DIR/return-type-suggestion.rs:9:9
|
LL | Ok(())
| ^^^^^^- help: consider using a semicolon here: `;`
@ -18,6 +9,6 @@ LL | Ok(())
= note: expected unit type `()`
found enum `Result<(), _>`
error: aborting due to previous error; 1 warning emitted
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -3,7 +3,6 @@
// revisions: current next
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
trait A {
async fn e() {

View file

@ -7,14 +7,6 @@ LL | #![feature(return_type_notation)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/issue-110963-early.rs:5:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
error: higher-ranked lifetime error
--> $DIR/issue-110963-early.rs:15:5
|
@ -41,5 +33,5 @@ LL | | });
|
= note: could not prove `[async block@$DIR/issue-110963-early.rs:15:11: 20:6]: Send`
error: aborting due to 2 previous errors; 2 warnings emitted
error: aborting due to 2 previous errors; 1 warning emitted

View file

@ -4,7 +4,6 @@
#![feature(return_type_notation)]
//~^ WARN the feature `return_type_notation` is incomplete
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete
trait HealthCheck {
async fn check(&mut self) -> bool;

View file

@ -7,13 +7,5 @@ LL | #![feature(return_type_notation)]
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/issue-110963-late.rs:6:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
warning: 2 warnings emitted
warning: 1 warning emitted

View file

@ -0,0 +1,13 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
fn check(_: impl std::marker::ConstParamTy) {}
fn main() {
check(main); //~ error: `fn() {main}` can't be used as a const parameter type
check(|| {}); //~ error: `[closure@$DIR/const_param_ty_bad.rs:8:11: 8:13]` can't be used as a const parameter type
check(main as fn()); //~ error: `fn()` can't be used as a const parameter type
check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type
check(&mut () as *mut ()); //~ error: `*mut ()` can't be used as a const parameter type
check(&() as *const ()); //~ error: `*const ()` can't be used as a const parameter type
}

View file

@ -0,0 +1,87 @@
error[E0277]: `fn() {main}` can't be used as a const parameter type
--> $DIR/const_param_ty_bad.rs:7:11
|
LL | check(main);
| ----- ^^^^ the trait `ConstParamTy` is not implemented for fn item `fn() {main}`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check`
--> $DIR/const_param_ty_bad.rs:4:18
|
LL | fn check(_: impl std::marker::ConstParamTy) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: `[closure@$DIR/const_param_ty_bad.rs:8:11: 8:13]` can't be used as a const parameter type
--> $DIR/const_param_ty_bad.rs:8:11
|
LL | check(|| {});
| ----- ^^^^^ the trait `ConstParamTy` is not implemented for closure `[closure@$DIR/const_param_ty_bad.rs:8:11: 8:13]`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check`
--> $DIR/const_param_ty_bad.rs:4:18
|
LL | fn check(_: impl std::marker::ConstParamTy) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: `fn()` can't be used as a const parameter type
--> $DIR/const_param_ty_bad.rs:9:11
|
LL | check(main as fn());
| ----- ^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `fn()`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check`
--> $DIR/const_param_ty_bad.rs:4:18
|
LL | fn check(_: impl std::marker::ConstParamTy) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: `&mut ()` can't be used as a const parameter type
--> $DIR/const_param_ty_bad.rs:10:11
|
LL | check(&mut ());
| ----- ^^^^^^^ the trait `ConstParamTy` is not implemented for `&mut ()`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check`
--> $DIR/const_param_ty_bad.rs:4:18
|
LL | fn check(_: impl std::marker::ConstParamTy) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: `*mut ()` can't be used as a const parameter type
--> $DIR/const_param_ty_bad.rs:11:11
|
LL | check(&mut () as *mut ());
| ----- ^^^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*mut ()`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check`
--> $DIR/const_param_ty_bad.rs:4:18
|
LL | fn check(_: impl std::marker::ConstParamTy) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: `*const ()` can't be used as a const parameter type
--> $DIR/const_param_ty_bad.rs:12:11
|
LL | check(&() as *const ());
| ----- ^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*const ()`
| |
| required by a bound introduced by this call
|
note: required by a bound in `check`
--> $DIR/const_param_ty_bad.rs:4:18
|
LL | fn check(_: impl std::marker::ConstParamTy) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,12 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#[derive(PartialEq, Eq)]
struct NotParam;
fn check<T: std::marker::ConstParamTy>() {}
fn main() {
check::<[NotParam; 0]>();
//~^ error: `NotParam` can't be used as a const parameter type
}

View file

@ -0,0 +1,16 @@
error[E0277]: `NotParam` can't be used as a const parameter type
--> $DIR/const_param_ty_bad_empty_array.rs:10:13
|
LL | check::<[NotParam; 0]>();
| ^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`
|
= note: required for `[NotParam; 0]` to implement `ConstParamTy`
note: required by a bound in `check`
--> $DIR/const_param_ty_bad_empty_array.rs:7:13
|
LL | fn check<T: std::marker::ConstParamTy>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,13 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#[derive(PartialEq, Eq)]
struct NotParam;
fn check<T: std::marker::ConstParamTy + ?Sized>() {}
fn main() {
check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type
check::<[NotParam]>(); //~ error: `NotParam` can't be used as a const parameter type
check::<[NotParam; 17]>(); //~ error: `NotParam` can't be used as a const parameter type
}

View file

@ -0,0 +1,42 @@
error[E0277]: `NotParam` can't be used as a const parameter type
--> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13
|
LL | check::<&NotParam>();
| ^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`
|
= note: required for `&NotParam` to implement `ConstParamTy`
note: required by a bound in `check`
--> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13
|
LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: `NotParam` can't be used as a const parameter type
--> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13
|
LL | check::<[NotParam]>();
| ^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`
|
= note: required for `[NotParam]` to implement `ConstParamTy`
note: required by a bound in `check`
--> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13
|
LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error[E0277]: `NotParam` can't be used as a const parameter type
--> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13
|
LL | check::<[NotParam; 17]>();
| ^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`
|
= note: required for `[NotParam; 17]` to implement `ConstParamTy`
note: required by a bound in `check`
--> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13
|
LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,43 @@
// check-pass
#![allow(incomplete_features)]
#![feature(adt_const_params)]
use std::marker::ConstParamTy;
#[derive(PartialEq, Eq)]
struct S<T> {
field: u8,
gen: T,
}
impl<T: ConstParamTy> ConstParamTy for S<T> {}
fn check<T: ConstParamTy + ?Sized>() {}
fn main() {
check::<u8>();
check::<u16>();
check::<u32>();
check::<u64>();
check::<u128>();
check::<i8>();
check::<i16>();
check::<i32>();
check::<i64>();
check::<i128>();
check::<char>();
check::<bool>();
check::<str>();
check::<&u8>();
check::<&str>();
check::<[usize]>();
check::<[u16; 0]>();
check::<[u8; 42]>();
check::<S<u8>>();
check::<S<[&[bool]; 8]>>();
// FIXME: test tuples
}

View file

@ -0,0 +1,13 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#[derive(PartialEq, Eq)]
struct NotParam;
#[derive(PartialEq, Eq)]
struct CantParam(NotParam);
impl std::marker::ConstParamTy for CantParam {}
//~^ error: the trait `ConstParamTy` cannot be implemented for this type
fn main() {}

View file

@ -0,0 +1,12 @@
error[E0204]: the trait `ConstParamTy` cannot be implemented for this type
--> $DIR/const_param_ty_impl_bad_field.rs:10:36
|
LL | struct CantParam(NotParam);
| -------- this field does not implement `ConstParamTy`
LL |
LL | impl std::marker::ConstParamTy for CantParam {}
| ^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0204`.

View file

@ -0,0 +1,17 @@
#![allow(incomplete_features)]
#![feature(adt_const_params)]
#[derive(PartialEq, Eq)]
struct ImplementsConstParamTy;
impl std::marker::ConstParamTy for ImplementsConstParamTy {}
struct CantParam(ImplementsConstParamTy);
impl std::marker::ConstParamTy for CantParam {}
//~^ error: the type `CantParam` does not `#[derive(Eq)]`
fn check<T: std::marker::ConstParamTy>() {}
fn main() {
check::<ImplementsConstParamTy>();
}

View file

@ -0,0 +1,12 @@
error[E0277]: the type `CantParam` does not `#[derive(Eq)]`
--> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36
|
LL | impl std::marker::ConstParamTy for CantParam {}
| ^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParam`
|
note: required by a bound in `ConstParamTy`
--> $SRC_DIR/core/src/marker.rs:LL:COL
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -10,6 +10,7 @@ pub trait Parse {
pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
//~^ ERROR expected associated constant bound
//~| ERROR expected associated constant bound
//~| ERROR expected type
fn no_help() -> Mode::Cool {}

View file

@ -8,7 +8,7 @@ LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
| help: try using the variant's enum: `Mode`
error[E0573]: expected type, found variant `Mode::Cool`
--> $DIR/assoc_const_eq_diagnostic.rs:15:17
--> $DIR/assoc_const_eq_diagnostic.rs:16:17
|
LL | fn no_help() -> Mode::Cool {}
| ^^^^^^^^^^
@ -28,6 +28,18 @@ note: associated constant defined here
LL | const MODE: Mode;
| ^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
error: expected associated constant bound, found type
--> $DIR/assoc_const_eq_diagnostic.rs:11:28
|
LL | pub trait CoolStuff: Parse<MODE = Mode::Cool> {}
| ^^^^^^^^^^^^^^^^^ help: if equating a const, try wrapping with braces: `MODE = { const }`
|
note: associated constant defined here
--> $DIR/assoc_const_eq_diagnostic.rs:8:5
|
LL | const MODE: Mode;
| ^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0573`.

View file

@ -3,7 +3,7 @@
#![cfg_attr(full, feature(adt_const_params))]
#![cfg_attr(full, allow(incomplete_features))]
struct Foo<const N: [u8; { //[min]~ ERROR `[u8; _]` is forbidden
struct Foo<const N: [u8; {
struct Foo<const N: usize>;
impl<const N: usize> Foo<N> {
@ -15,5 +15,9 @@ fn value() -> usize {
Foo::<17>::value()
//~^ ERROR cannot call non-const fn
}]>;
//[min]~^^^^^^^^^^^^ ERROR `[u8; {
// N.B. it is important that the comment above is not inside the array length,
// otherwise it may check for itself, instead of the actual error
fn main() {}

View file

@ -1,5 +1,6 @@
trait Foo: Iterator<Item = i32, Item = i32> {}
//~^ ERROR is already specified
//~| ERROR is already specified
type Unit = ();

View file

@ -7,13 +7,21 @@ LL | trait Foo: Iterator<Item = i32, Item = i32> {}
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/E0719.rs:6:42
--> $DIR/E0719.rs:1:33
|
LL | trait Foo: Iterator<Item = i32, Item = i32> {}
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first
error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified
--> $DIR/E0719.rs:7:42
|
LL | fn test() -> Box<dyn Iterator<Item = (), Item = Unit>> {
| --------- ^^^^^^^^^^^ re-bound here
| |
| `Item` bound here first
error: aborting due to 2 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0719`.

View file

@ -1,3 +0,0 @@
#![debugger_visualizer(natvis_file = "auxiliary/debugger-visualizer.natvis")] //~ ERROR the `#[debugger_visualizer]` attribute is an experimental feature
fn main() {}

View file

@ -1,12 +0,0 @@
error[E0658]: the `#[debugger_visualizer]` attribute is an experimental feature
--> $DIR/feature-gate-debugger-visualizer.rs:1:1
|
LL | #![debugger_visualizer(natvis_file = "auxiliary/debugger-visualizer.natvis")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #95939 <https://github.com/rust-lang/rust/issues/95939> for more information
= help: add `#![feature(debugger_visualizer)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -1,5 +1,5 @@
error[E0658]: return type notation is experimental
--> $DIR/feature-gate-return_type_notation.rs:15:17
--> $DIR/feature-gate-return_type_notation.rs:14:17
|
LL | fn foo<T: Trait<m(): Send>>() {}
| ^^^^^^^^^
@ -7,17 +7,8 @@ LL | fn foo<T: Trait<m(): Send>>() {}
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
= help: add `#![feature(return_type_notation)]` to the crate attributes to enable
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/feature-gate-return_type_notation.rs:7:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
error: parenthesized generic arguments cannot be used in associated type constraints
--> $DIR/feature-gate-return_type_notation.rs:15:17
--> $DIR/feature-gate-return_type_notation.rs:14:17
|
LL | fn foo<T: Trait<m(): Send>>() {}
| ^--
@ -25,12 +16,12 @@ LL | fn foo<T: Trait<m(): Send>>() {}
| help: remove these parentheses
error[E0220]: associated type `m` not found for `Trait`
--> $DIR/feature-gate-return_type_notation.rs:15:17
--> $DIR/feature-gate-return_type_notation.rs:14:17
|
LL | fn foo<T: Trait<m(): Send>>() {}
| ^ associated type `m` not found
error: aborting due to 3 previous errors; 1 warning emitted
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0220, E0658.
For more information about an error, try `rustc --explain E0220`.

View file

@ -1,14 +1,5 @@
warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/feature-gate-return_type_notation.rs:7:12
|
LL | #![feature(async_fn_in_trait)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
= note: `#[warn(incomplete_features)]` on by default
warning: return type notation is experimental
--> $DIR/feature-gate-return_type_notation.rs:15:17
--> $DIR/feature-gate-return_type_notation.rs:14:17
|
LL | fn foo<T: Trait<m(): Send>>() {}
| ^^^^^^^^^
@ -18,5 +9,5 @@ LL | fn foo<T: Trait<m(): Send>>() {}
= warning: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: 2 warnings emitted
warning: 1 warning emitted

View file

@ -5,7 +5,6 @@
// Since we're not adding new syntax, `cfg`'d out RTN must pass.
#![feature(async_fn_in_trait)]
//~^ WARN the feature `async_fn_in_trait` is incomplete
trait Trait {
async fn m();

View file

@ -17,7 +17,7 @@ fn main() {
let _ = format!("}");
//~^ ERROR invalid format string: unmatched `}` found
let _ = format!("{\\}");
//~^ ERROR invalid format string: expected `'}'`, found `'\\'`
//~^ ERROR invalid format string: expected `'}'`, found `'\'`
let _ = format!("\n\n\n{\n\n\n");
//~^ ERROR invalid format string
let _ = format!(r###"

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