Auto merge of #98669 - Dylan-DPC:rollup-8uzhcip, r=Dylan-DPC
Rollup of 7 pull requests Successful merges: - #98415 (Migrate some `rustc_borrowck` diagnostics to `SessionDiagnostic`) - #98479 (Add `fetch_not` method on `AtomicBool`) - #98499 (Erase regions in New Abstract Consts) - #98516 (library: fix uefi va_list type definition) - #98554 (Fix box with custom allocator in miri) - #98607 (Clean up arg mismatch diagnostic, generalize tuple wrap suggestion) - #98625 (emit Retag for compound types with reference fields) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
3fcf43bb0f
39 changed files with 512 additions and 272 deletions
|
@ -3595,6 +3595,7 @@ dependencies = [
|
|||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_lexer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_mir_dataflow",
|
||||
"rustc_serialize",
|
||||
|
|
|
@ -19,6 +19,7 @@ rustc_hir = { path = "../rustc_hir" }
|
|||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_const_eval = { path = "../rustc_const_eval" }
|
||||
rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
|
||||
|
|
|
@ -19,6 +19,9 @@ use std::fmt;
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::region_infer::values::RegionElement;
|
||||
use crate::session_diagnostics::HigherRankedErrorCause;
|
||||
use crate::session_diagnostics::HigherRankedLifetimeError;
|
||||
use crate::session_diagnostics::HigherRankedSubtypeError;
|
||||
use crate::MirBorrowckCtxt;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -69,7 +72,7 @@ impl<'tcx> UniverseInfo<'tcx> {
|
|||
// up in the existing UI tests. Consider investigating this
|
||||
// some more.
|
||||
mbcx.buffer_error(
|
||||
mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
|
||||
mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -216,9 +219,12 @@ impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
|
|||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
|
||||
err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
|
||||
err
|
||||
tcx.sess.create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotProve {
|
||||
predicate: self.canonical_query.value.value.predicate.to_string(),
|
||||
}),
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
|
@ -263,9 +269,12 @@ where
|
|||
tcx: TyCtxt<'tcx>,
|
||||
span: Span,
|
||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
|
||||
err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
|
||||
err
|
||||
tcx.sess.create_err(HigherRankedLifetimeError {
|
||||
cause: Some(HigherRankedErrorCause::CouldNotNormalize {
|
||||
value: self.canonical_query.value.value.value.to_string(),
|
||||
}),
|
||||
span,
|
||||
})
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
|
@ -326,7 +335,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
|
|||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
|
||||
tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
|
@ -366,7 +375,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
|||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||
// FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
|
||||
// and is only the fallback when the nice error fails. Consider improving this some more.
|
||||
tcx.sess.struct_span_err(span, "higher-ranked lifetime error for opaque type!")
|
||||
tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
|
||||
}
|
||||
|
||||
fn base_universe(&self) -> ty::UniverseIndex {
|
||||
|
|
|
@ -24,6 +24,7 @@ use rustc_span::symbol::Ident;
|
|||
use rustc_span::Span;
|
||||
|
||||
use crate::borrowck_errors;
|
||||
use crate::session_diagnostics::GenericDoesNotLiveLongEnough;
|
||||
|
||||
use super::{OutlivesSuggestionBuilder, RegionName};
|
||||
use crate::region_infer::BlameConstraint;
|
||||
|
@ -196,9 +197,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
// to report it; we could probably handle it by
|
||||
// iterating over the universal regions and reporting
|
||||
// an error that multiple bounds are required.
|
||||
self.buffer_error(self.infcx.tcx.sess.struct_span_err(
|
||||
type_test_span,
|
||||
&format!("`{}` does not live long enough", type_test.generic_kind),
|
||||
self.buffer_error(self.infcx.tcx.sess.create_err(
|
||||
GenericDoesNotLiveLongEnough {
|
||||
kind: type_test.generic_kind.to_string(),
|
||||
span: type_test_span,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ mod places_conflict;
|
|||
mod prefixes;
|
||||
mod region_infer;
|
||||
mod renumber;
|
||||
mod session_diagnostics;
|
||||
mod type_check;
|
||||
mod universal_regions;
|
||||
mod used_muts;
|
||||
|
|
44
compiler/rustc_borrowck/src/session_diagnostics.rs
Normal file
44
compiler/rustc_borrowck/src/session_diagnostics.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::move_unsized, code = "E0161")]
|
||||
pub(crate) struct MoveUnsized<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::higher_ranked_lifetime_error)]
|
||||
pub(crate) struct HigherRankedLifetimeError {
|
||||
#[subdiagnostic]
|
||||
pub cause: Option<HigherRankedErrorCause>,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionSubdiagnostic)]
|
||||
pub(crate) enum HigherRankedErrorCause {
|
||||
#[note(borrowck::could_not_prove)]
|
||||
CouldNotProve { predicate: String },
|
||||
#[note(borrowck::could_not_normalize)]
|
||||
CouldNotNormalize { value: String },
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::higher_ranked_subtype_error)]
|
||||
pub(crate) struct HigherRankedSubtypeError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(SessionDiagnostic)]
|
||||
#[error(borrowck::generic_does_not_live_long_enough)]
|
||||
pub(crate) struct GenericDoesNotLiveLongEnough {
|
||||
pub kind: String,
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
|
@ -9,7 +9,6 @@ use hir::OpaqueTyOrigin;
|
|||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::vec_map::VecMap;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
@ -48,6 +47,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
|||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
||||
use crate::session_diagnostics::MoveUnsized;
|
||||
use crate::{
|
||||
borrow_set::BorrowSet,
|
||||
constraints::{OutlivesConstraint, OutlivesConstraintSet},
|
||||
|
@ -1780,19 +1780,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// slot or local, so to find all unsized rvalues it is enough
|
||||
// to check all temps, return slots and locals.
|
||||
if self.reported_errors.replace((ty, span)).is_none() {
|
||||
let mut diag = struct_span_err!(
|
||||
self.tcx().sess,
|
||||
span,
|
||||
E0161,
|
||||
"cannot move a value of type {0}: the size of {0} \
|
||||
cannot be statically determined",
|
||||
ty
|
||||
);
|
||||
|
||||
// While this is located in `nll::typeck` this error is not
|
||||
// an NLL error, it's a required check to prevent creation
|
||||
// of unsized rvalues in a call expression.
|
||||
diag.emit();
|
||||
self.tcx().sess.emit_err(MoveUnsized { ty, span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,22 +366,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
||||
assert_eq!(def_a, def_b);
|
||||
if def_a.is_box() || def_b.is_box() {
|
||||
if !def_a.is_box() || !def_b.is_box() {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"invalid unsizing between {:?} -> {:?}",
|
||||
src.layout.ty,
|
||||
cast_ty.ty
|
||||
);
|
||||
}
|
||||
return self.unsize_into_ptr(
|
||||
src,
|
||||
dest,
|
||||
src.layout.ty.boxed_ty(),
|
||||
cast_ty.ty.boxed_ty(),
|
||||
);
|
||||
}
|
||||
|
||||
// unsizing of generic struct with pointer fields
|
||||
// Example: `Arc<T>` -> `Arc<Trait>`
|
||||
|
|
|
@ -594,7 +594,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
Ok(true)
|
||||
}
|
||||
ty::Adt(def, ..) if def.is_box() => {
|
||||
self.check_safe_pointer(value, "box")?;
|
||||
let unique = self.ecx.operand_field(value, 0)?;
|
||||
let nonnull = self.ecx.operand_field(&unique, 0)?;
|
||||
let ptr = self.ecx.operand_field(&nonnull, 0)?;
|
||||
self.check_safe_pointer(&ptr, "box")?;
|
||||
|
||||
// Check other fields of Box
|
||||
self.walk_value(value)?;
|
||||
Ok(true)
|
||||
}
|
||||
ty::FnPtr(_sig) => {
|
||||
|
|
18
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
Normal file
18
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
Normal file
|
@ -0,0 +1,18 @@
|
|||
borrowck-move-unsized =
|
||||
cannot move a value of type `{$ty}`
|
||||
.label = the size of `{$ty}` cannot be statically determined
|
||||
|
||||
borrowck-higher-ranked-lifetime-error =
|
||||
higher-ranked lifetime error
|
||||
|
||||
borrowck-could-not-prove =
|
||||
could not prove `{$predicate}`
|
||||
|
||||
borrowck-could-not-normalize =
|
||||
could not normalize `{$value}`
|
||||
|
||||
borrowck-higher-ranked-subtype-error =
|
||||
higher-ranked subtype error
|
||||
|
||||
generic-does-not-live-long-enough =
|
||||
`{$kind}` does not live long enough
|
|
@ -35,6 +35,7 @@ fluent_messages! {
|
|||
privacy => "../locales/en-US/privacy.ftl",
|
||||
typeck => "../locales/en-US/typeck.ftl",
|
||||
builtin_macros => "../locales/en-US/builtin_macros.ftl",
|
||||
borrowck => "../locales/en-US/borrowck.ftl",
|
||||
}
|
||||
|
||||
pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
|
||||
|
|
|
@ -281,9 +281,19 @@ pub trait Emitter {
|
|||
let message = bundle.get_message(&identifier).expect("missing diagnostic in fluent bundle");
|
||||
let value = match attr {
|
||||
Some(attr) => {
|
||||
message.get_attribute(attr).expect("missing attribute in fluent message").value()
|
||||
if let Some(attr) = message.get_attribute(attr) {
|
||||
attr.value()
|
||||
} else {
|
||||
panic!("missing attribute `{attr}` in fluent message `{identifier}`")
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let Some(value) = message.value() {
|
||||
value
|
||||
} else {
|
||||
panic!("missing value in fluent message `{identifier}`")
|
||||
}
|
||||
}
|
||||
None => message.value().expect("missing value in fluent message"),
|
||||
};
|
||||
|
||||
let mut err = vec![];
|
||||
|
|
|
@ -342,8 +342,8 @@ pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
|||
)
|
||||
| (&ty::Infer(ty::InferTy::TyVar(_)), _)
|
||||
| (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
|
||||
(&ty::Ref(reg_a, ty_a, mut_a), &ty::Ref(reg_b, ty_b, mut_b)) => {
|
||||
reg_a == reg_b && mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b)
|
||||
(&ty::Ref(_, ty_a, mut_a), &ty::Ref(_, ty_b, mut_b)) => {
|
||||
mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b)
|
||||
}
|
||||
_ => a == b,
|
||||
}
|
||||
|
|
|
@ -33,8 +33,9 @@ fn is_stable(place: PlaceRef<'_>) -> bool {
|
|||
})
|
||||
}
|
||||
|
||||
/// Determine whether this type may be a reference (or box), and thus needs retagging.
|
||||
fn may_be_reference(ty: Ty<'_>) -> bool {
|
||||
/// Determine whether this type may contain a reference (or box), and thus needs retagging.
|
||||
/// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this.
|
||||
fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> bool {
|
||||
match ty.kind() {
|
||||
// Primitive types that are not references
|
||||
ty::Bool
|
||||
|
@ -50,8 +51,20 @@ fn may_be_reference(ty: Ty<'_>) -> bool {
|
|||
// References
|
||||
ty::Ref(..) => true,
|
||||
ty::Adt(..) if ty.is_box() => true,
|
||||
// Compound types are not references
|
||||
ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::Adt(..) => false,
|
||||
// Compound types: recurse
|
||||
ty::Array(ty, _) | ty::Slice(ty) => {
|
||||
// This does not branch so we keep the depth the same.
|
||||
may_contain_reference(*ty, depth, tcx)
|
||||
}
|
||||
ty::Tuple(tys) => {
|
||||
depth == 0 || tys.iter().any(|ty| may_contain_reference(ty, depth - 1, tcx))
|
||||
}
|
||||
ty::Adt(adt, subst) => {
|
||||
depth == 0
|
||||
|| adt.variants().iter().any(|v| {
|
||||
v.fields.iter().any(|f| may_contain_reference(f.ty(tcx, subst), depth - 1, tcx))
|
||||
})
|
||||
}
|
||||
// Conservative fallback
|
||||
_ => true,
|
||||
}
|
||||
|
@ -83,7 +96,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
|
|||
// FIXME: Instead of giving up for unstable places, we should introduce
|
||||
// a temporary and retag on that.
|
||||
is_stable(place.as_ref())
|
||||
&& may_be_reference(place.ty(&*local_decls, tcx).ty)
|
||||
&& may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx)
|
||||
&& is_not_temp(&local_decls[place.local])
|
||||
};
|
||||
let place_base_raw = |place: &Place<'tcx>| {
|
||||
|
|
|
@ -236,7 +236,7 @@ impl<'tcx> AbstractConst<'tcx> {
|
|||
) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
|
||||
let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
|
||||
debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
|
||||
Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs }))
|
||||
Ok(inner.map(|inner| AbstractConst { inner, substs: tcx.erase_regions(uv.substs) }))
|
||||
}
|
||||
|
||||
pub fn from_const(
|
||||
|
@ -416,6 +416,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||
// `AbstractConst`s should not contain any promoteds as they require references which
|
||||
// are not allowed.
|
||||
assert_eq!(ct.promoted, None);
|
||||
assert_eq!(ct, self.tcx.erase_regions(ct));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
|
|||
use rustc_infer::infer::InferOk;
|
||||
use rustc_infer::infer::TypeTrace;
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
|
@ -35,12 +34,6 @@ use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpres
|
|||
use std::iter;
|
||||
use std::slice;
|
||||
|
||||
enum TupleMatchFound {
|
||||
None,
|
||||
Single,
|
||||
/// Beginning and end Span
|
||||
Multiple(Span, Span),
|
||||
}
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(in super::super) fn check_casts(&self) {
|
||||
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
||||
|
@ -216,14 +209,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let minimum_input_count = expected_input_tys.len();
|
||||
let provided_arg_count = provided_args.len();
|
||||
|
||||
// We'll also want to keep track of the fully coerced argument types, for an awkward hack near the end
|
||||
// FIXME(compiler-errors): Get rid of this, actually.
|
||||
let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count];
|
||||
|
||||
// We introduce a helper function to demand that a given argument satisfy a given input
|
||||
// This is more complicated than just checking type equality, as arguments could be coerced
|
||||
// This version writes those types back so further type checking uses the narrowed types
|
||||
let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| {
|
||||
let demand_compatible = |idx| {
|
||||
let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
|
||||
let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
|
||||
let provided_arg = &provided_args[idx];
|
||||
|
@ -242,9 +231,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
|
||||
let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
|
||||
|
||||
// Keep track of these for below
|
||||
final_arg_types[idx] = Some((checked_ty, coerced_ty));
|
||||
|
||||
// Cause selection errors caused by resolving a single argument to point at the
|
||||
// argument and not the call. This lets us customize the span pointed to in the
|
||||
// fulfillment error to be more accurate.
|
||||
|
@ -253,16 +239,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
|
||||
self.point_at_arg_instead_of_call_if_possible(
|
||||
errors,
|
||||
&final_arg_types,
|
||||
call_expr,
|
||||
call_span,
|
||||
provided_args,
|
||||
&expected_input_tys,
|
||||
);
|
||||
});
|
||||
|
||||
// Make sure we store the resolved type
|
||||
final_arg_types[idx] = Some((checked_ty, coerced_ty));
|
||||
|
||||
let coerce_error = self
|
||||
.try_coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None)
|
||||
.err();
|
||||
|
@ -320,10 +303,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
|
||||
self.point_at_arg_instead_of_call_if_possible(
|
||||
errors,
|
||||
&final_arg_types,
|
||||
call_expr,
|
||||
call_span,
|
||||
&provided_args,
|
||||
&expected_input_tys,
|
||||
);
|
||||
})
|
||||
}
|
||||
|
@ -352,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let compatible = demand_compatible(idx, &mut final_arg_types);
|
||||
let compatible = demand_compatible(idx);
|
||||
let is_compatible = matches!(compatible, Compatibility::Compatible);
|
||||
compatibility_diagonal[idx] = compatible;
|
||||
|
||||
|
@ -445,72 +428,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
None => "function",
|
||||
};
|
||||
|
||||
let try_tuple_wrap_args = || {
|
||||
// The case where we expect a single tuple and wrapping all the args
|
||||
// in parentheses (or adding a comma to already existing parentheses)
|
||||
// will result in a tuple that satisfies the call.
|
||||
// This isn't super ideal code, because we copy code from elsewhere
|
||||
// and somewhat duplicate this. We also delegate to the general type
|
||||
// mismatch suggestions for the single arg case.
|
||||
match self.suggested_tuple_wrap(&expected_input_tys, provided_args) {
|
||||
TupleMatchFound::Single => {
|
||||
let expected_ty = expected_input_tys[0];
|
||||
let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap();
|
||||
let expected_ty = self.resolve_vars_if_possible(expected_ty);
|
||||
let provided_ty = self.resolve_vars_if_possible(provided_ty);
|
||||
let cause = &self.misc(provided_args[0].span);
|
||||
let compatibility = demand_compatible(0, &mut final_arg_types);
|
||||
let type_error = match compatibility {
|
||||
Compatibility::Incompatible(Some(error)) => error,
|
||||
_ => TypeError::Mismatch,
|
||||
};
|
||||
let trace = TypeTrace::types(cause, true, expected_ty, provided_ty);
|
||||
let mut err = self.report_and_explain_type_error(trace, &type_error);
|
||||
self.emit_coerce_suggestions(
|
||||
&mut err,
|
||||
&provided_args[0],
|
||||
final_arg_types[0].map(|ty| ty.0).unwrap(),
|
||||
final_arg_types[0].map(|ty| ty.1).unwrap(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
err.span_label(
|
||||
full_call_span,
|
||||
format!("arguments to this {} are incorrect", call_name),
|
||||
);
|
||||
// Call out where the function is defined
|
||||
label_fn_like(tcx, &mut err, fn_def_id);
|
||||
err.emit();
|
||||
return true;
|
||||
}
|
||||
TupleMatchFound::Multiple(start, end) => {
|
||||
let mut err = tcx.sess.struct_span_err_with_code(
|
||||
full_call_span,
|
||||
&format!(
|
||||
"this {} takes {}{} but {} {} supplied",
|
||||
call_name,
|
||||
if c_variadic { "at least " } else { "" },
|
||||
potentially_plural_count(minimum_input_count, "argument"),
|
||||
potentially_plural_count(provided_arg_count, "argument"),
|
||||
if provided_arg_count == 1 { "was" } else { "were" }
|
||||
),
|
||||
DiagnosticId::Error(err_code.to_owned()),
|
||||
);
|
||||
// Call out where the function is defined
|
||||
label_fn_like(tcx, &mut err, fn_def_id);
|
||||
err.multipart_suggestion(
|
||||
"use parentheses to construct a tuple",
|
||||
vec![(start, '('.to_string()), (end, ')'.to_string())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
err.emit();
|
||||
return true;
|
||||
}
|
||||
TupleMatchFound::None => {}
|
||||
}
|
||||
false
|
||||
};
|
||||
|
||||
let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal);
|
||||
let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic {
|
||||
minimum_input_count
|
||||
|
@ -541,7 +458,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
c_variadic,
|
||||
err_code,
|
||||
fn_def_id,
|
||||
try_tuple_wrap_args,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -558,7 +474,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
c_variadic: bool,
|
||||
err_code: &str,
|
||||
fn_def_id: Option<DefId>,
|
||||
try_tuple_wrap_args: impl FnOnce() -> bool,
|
||||
) {
|
||||
// Don't print if it has error types or is just plain `_`
|
||||
fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
|
||||
|
@ -578,7 +493,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx];
|
||||
// If either is an error type, we defy the usual convention and consider them to *not* be
|
||||
// coercible. This prevents our error message heuristic from trying to pass errors into
|
||||
// coercible. This prevents our error message heuristic from trying to pass errors into
|
||||
// every argument.
|
||||
if (formal_input_ty, expected_input_ty).references_error() {
|
||||
return Compatibility::Incompatible(None);
|
||||
|
@ -599,16 +514,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return Compatibility::Incompatible(None);
|
||||
}
|
||||
|
||||
let subtyping_result = self
|
||||
.at(&self.misc(provided_arg.span), self.param_env)
|
||||
.sup(formal_input_ty, coerced_ty);
|
||||
// Using probe here, since we don't want this subtyping to affect inference.
|
||||
let subtyping_error = self.probe(|_| {
|
||||
self.at(&self.misc(provided_arg.span), self.param_env)
|
||||
.sup(formal_input_ty, coerced_ty)
|
||||
.err()
|
||||
});
|
||||
|
||||
// Same as above: if either the coerce type or the checked type is an error type,
|
||||
// consider them *not* compatible.
|
||||
let references_error = (coerced_ty, checked_ty).references_error();
|
||||
match (references_error, &subtyping_result) {
|
||||
(false, Ok(_)) => Compatibility::Compatible,
|
||||
_ => Compatibility::Incompatible(subtyping_result.err()),
|
||||
match (references_error, subtyping_error) {
|
||||
(false, None) => Compatibility::Compatible,
|
||||
(_, subtyping_error) => Compatibility::Incompatible(subtyping_error),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -629,9 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
.iter()
|
||||
.map(|expr| {
|
||||
let ty = self
|
||||
.in_progress_typeck_results
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.typeck_results
|
||||
.borrow()
|
||||
.expr_ty_adjusted_opt(*expr)
|
||||
.unwrap_or_else(|| tcx.ty_error());
|
||||
|
@ -639,6 +555,97 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
// First, check if we just need to wrap some arguments in a tuple.
|
||||
if let Some((mismatch_idx, terr)) =
|
||||
compatibility_diagonal.iter().enumerate().find_map(|(i, c)| {
|
||||
if let Compatibility::Incompatible(Some(terr)) = c { Some((i, terr)) } else { None }
|
||||
})
|
||||
{
|
||||
// Is the first bad expected argument a tuple?
|
||||
// Do we have as many extra provided arguments as the tuple's length?
|
||||
// If so, we might have just forgotten to wrap some args in a tuple.
|
||||
if let Some(ty::Tuple(tys)) =
|
||||
formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
|
||||
&& provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
|
||||
{
|
||||
// Wrap up the N provided arguments starting at this position in a tuple.
|
||||
let provided_as_tuple = tcx.mk_tup(
|
||||
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
|
||||
);
|
||||
|
||||
let mut satisfied = true;
|
||||
// Check if the newly wrapped tuple + rest of the arguments are compatible.
|
||||
for ((_, expected_ty), provided_ty) in std::iter::zip(
|
||||
formal_and_expected_inputs.iter().skip(mismatch_idx),
|
||||
[provided_as_tuple].into_iter().chain(
|
||||
provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
|
||||
),
|
||||
) {
|
||||
if !self.can_coerce(provided_ty, *expected_ty) {
|
||||
satisfied = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If they're compatible, suggest wrapping in an arg, and we're done!
|
||||
// Take some care with spans, so we don't suggest wrapping a macro's
|
||||
// innards in parenthesis, for example.
|
||||
if satisfied
|
||||
&& let Some(lo) =
|
||||
provided_args[mismatch_idx.into()].span.find_ancestor_inside(error_span)
|
||||
&& let Some(hi) = provided_args[(mismatch_idx + tys.len() - 1).into()]
|
||||
.span
|
||||
.find_ancestor_inside(error_span)
|
||||
{
|
||||
let mut err;
|
||||
if tys.len() == 1 {
|
||||
// A tuple wrap suggestion actually occurs within,
|
||||
// so don't do anything special here.
|
||||
err = self.report_and_explain_type_error(
|
||||
TypeTrace::types(
|
||||
&self.misc(lo),
|
||||
true,
|
||||
formal_and_expected_inputs[mismatch_idx.into()].1,
|
||||
provided_arg_tys[mismatch_idx.into()].0,
|
||||
),
|
||||
terr,
|
||||
);
|
||||
err.span_label(
|
||||
full_call_span,
|
||||
format!("arguments to this {} are incorrect", call_name),
|
||||
);
|
||||
} else {
|
||||
err = tcx.sess.struct_span_err_with_code(
|
||||
full_call_span,
|
||||
&format!(
|
||||
"this {} takes {}{} but {} {} supplied",
|
||||
call_name,
|
||||
if c_variadic { "at least " } else { "" },
|
||||
potentially_plural_count(
|
||||
formal_and_expected_inputs.len(),
|
||||
"argument"
|
||||
),
|
||||
potentially_plural_count(provided_args.len(), "argument"),
|
||||
if provided_args.len() == 1 { "was" } else { "were" }
|
||||
),
|
||||
DiagnosticId::Error(err_code.to_owned()),
|
||||
);
|
||||
err.multipart_suggestion_verbose(
|
||||
"wrap these arguments in parentheses to construct a tuple",
|
||||
vec![
|
||||
(lo.shrink_to_lo(), "(".to_string()),
|
||||
(hi.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
};
|
||||
label_fn_like(tcx, &mut err, fn_def_id);
|
||||
err.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Okay, so here's where it gets complicated in regards to what errors
|
||||
// we emit and how.
|
||||
// There are 3 different "types" of errors we might encounter.
|
||||
|
@ -666,7 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
)
|
||||
.note(
|
||||
"we would appreciate a bug report: \
|
||||
https://github.com/rust-lang/rust-clippy/issues/new",
|
||||
https://github.com/rust-lang/rust/issues/new",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
@ -727,13 +734,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// Second, let's try tuple wrapping the args.
|
||||
// FIXME(compiler-errors): This is currently in its own closure because
|
||||
// I didn't want to factor it out.
|
||||
if try_tuple_wrap_args() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut err = if formal_and_expected_inputs.len() == provided_args.len() {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
|
@ -989,13 +989,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
String::new()
|
||||
};
|
||||
// FIXME(compiler-errors): Why do we get permutations with the same type?
|
||||
if expected_ty != provided_ty {
|
||||
labels.push((
|
||||
provided_span,
|
||||
format!("expected `{}`{}", expected_ty, provided_ty_name),
|
||||
));
|
||||
}
|
||||
labels.push((
|
||||
provided_span,
|
||||
format!("expected `{}`{}", expected_ty, provided_ty_name),
|
||||
));
|
||||
}
|
||||
|
||||
suggestion_text = match suggestion_text {
|
||||
|
@ -1043,10 +1040,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
needs_comma = true;
|
||||
}
|
||||
let suggestion_text =
|
||||
if let Some(provided_idx) = provided_idx
|
||||
let suggestion_text = if let Some(provided_idx) = provided_idx
|
||||
&& let (_, provided_span) = provided_arg_tys[*provided_idx]
|
||||
&& let Ok(arg_text) = source_map.span_to_snippet(provided_span.source_callsite()) {
|
||||
&& let Ok(arg_text) =
|
||||
source_map.span_to_snippet(provided_span.source_callsite())
|
||||
{
|
||||
arg_text
|
||||
} else {
|
||||
// Propose a placeholder of the correct type
|
||||
|
@ -1073,38 +1071,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.emit();
|
||||
}
|
||||
|
||||
fn suggested_tuple_wrap(
|
||||
&self,
|
||||
expected_input_tys: &[Ty<'tcx>],
|
||||
provided_args: &'tcx [hir::Expr<'tcx>],
|
||||
) -> TupleMatchFound {
|
||||
// Only handle the case where we expect only one tuple arg
|
||||
let [expected_arg_type] = expected_input_tys[..] else { return TupleMatchFound::None };
|
||||
let &ty::Tuple(expected_types) = self.resolve_vars_if_possible(expected_arg_type).kind()
|
||||
else { return TupleMatchFound::None };
|
||||
|
||||
// First check that there are the same number of types.
|
||||
if expected_types.len() != provided_args.len() {
|
||||
return TupleMatchFound::None;
|
||||
}
|
||||
|
||||
let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect();
|
||||
|
||||
let all_match = iter::zip(expected_types, supplied_types)
|
||||
.all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok());
|
||||
|
||||
if !all_match {
|
||||
return TupleMatchFound::None;
|
||||
}
|
||||
match provided_args {
|
||||
[] => TupleMatchFound::None,
|
||||
[_] => TupleMatchFound::Single,
|
||||
[first, .., last] => {
|
||||
TupleMatchFound::Multiple(first.span.shrink_to_lo(), last.span.shrink_to_hi())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AST fragment checking
|
||||
pub(in super::super) fn check_lit(
|
||||
&self,
|
||||
|
@ -1652,10 +1618,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
fn point_at_arg_instead_of_call_if_possible(
|
||||
&self,
|
||||
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
|
||||
final_arg_types: &[Option<(Ty<'tcx>, Ty<'tcx>)>],
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
call_sp: Span,
|
||||
args: &'tcx [hir::Expr<'tcx>],
|
||||
expected_tys: &[Ty<'tcx>],
|
||||
) {
|
||||
// We *do not* do this for desugared call spans to keep good diagnostics when involving
|
||||
// the `?` operator.
|
||||
|
@ -1663,7 +1629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
for error in errors {
|
||||
'outer: for error in errors {
|
||||
// Only if the cause is somewhere inside the expression we want try to point at arg.
|
||||
// Otherwise, it means that the cause is somewhere else and we should not change
|
||||
// anything because we can break the correct span.
|
||||
|
@ -1688,39 +1654,65 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
(result_code, code) = (code, parent);
|
||||
}
|
||||
}
|
||||
let self_: ty::subst::GenericArg<'_> = match unpeel_to_top(error.obligation.cause.code()) {
|
||||
ObligationCauseCode::BuiltinDerivedObligation(code) |
|
||||
ObligationCauseCode::DerivedObligation(code) => {
|
||||
code.parent_trait_pred.self_ty().skip_binder().into()
|
||||
}
|
||||
ObligationCauseCode::ImplDerivedObligation(code) => {
|
||||
code.derived.parent_trait_pred.self_ty().skip_binder().into()
|
||||
}
|
||||
_ if let ty::PredicateKind::Trait(predicate) =
|
||||
error.obligation.predicate.kind().skip_binder() => {
|
||||
let self_: ty::subst::GenericArg<'_> =
|
||||
match unpeel_to_top(error.obligation.cause.code()) {
|
||||
ObligationCauseCode::BuiltinDerivedObligation(code)
|
||||
| ObligationCauseCode::DerivedObligation(code) => {
|
||||
code.parent_trait_pred.self_ty().skip_binder().into()
|
||||
}
|
||||
ObligationCauseCode::ImplDerivedObligation(code) => {
|
||||
code.derived.parent_trait_pred.self_ty().skip_binder().into()
|
||||
}
|
||||
_ if let ty::PredicateKind::Trait(predicate) =
|
||||
error.obligation.predicate.kind().skip_binder() =>
|
||||
{
|
||||
predicate.self_ty().into()
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
_ => continue,
|
||||
};
|
||||
let self_ = self.resolve_vars_if_possible(self_);
|
||||
let ty_matches_self = |ty: Ty<'tcx>| ty.walk().any(|arg| arg == self_);
|
||||
|
||||
let typeck_results = self.typeck_results.borrow();
|
||||
|
||||
for (idx, arg) in args.iter().enumerate() {
|
||||
// Don't adjust the span if we already have a more precise span
|
||||
// within one of the args.
|
||||
if arg.span.contains(error.obligation.cause.span) {
|
||||
let references_arg =
|
||||
typeck_results.expr_ty_opt(arg).map_or(false, &ty_matches_self)
|
||||
|| expected_tys.get(idx).copied().map_or(false, &ty_matches_self);
|
||||
if references_arg && !arg.span.from_expansion() {
|
||||
error.obligation.cause.map_code(|parent_code| {
|
||||
ObligationCauseCode::FunctionArgumentObligation {
|
||||
arg_hir_id: args[idx].hir_id,
|
||||
call_hir_id: expr.hir_id,
|
||||
parent_code,
|
||||
}
|
||||
})
|
||||
}
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the argument position for all arguments that could have caused this
|
||||
// `FulfillmentError`.
|
||||
let mut referenced_in = final_arg_types
|
||||
.iter()
|
||||
let mut referenced_in: Vec<_> = std::iter::zip(expected_tys, args)
|
||||
.enumerate()
|
||||
.filter_map(|(i, arg)| match arg {
|
||||
Some((checked_ty, coerce_ty)) => Some([(i, *checked_ty), (i, *coerce_ty)]),
|
||||
_ => None,
|
||||
.flat_map(|(idx, (expected_ty, arg))| {
|
||||
if let Some(arg_ty) = typeck_results.expr_ty_opt(arg) {
|
||||
vec![(idx, arg_ty), (idx, *expected_ty)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.flat_map(|(i, ty)| {
|
||||
.filter_map(|(i, ty)| {
|
||||
let ty = self.resolve_vars_if_possible(ty);
|
||||
// We walk the argument type because the argument's type could have
|
||||
// been `Option<T>`, but the `FulfillmentError` references `T`.
|
||||
if ty.walk().any(|arg| arg == self_) { Some(i) } else { None }
|
||||
if ty_matches_self(ty) { Some(i) } else { None }
|
||||
})
|
||||
.collect::<Vec<usize>>();
|
||||
.collect();
|
||||
|
||||
// Both checked and coerced types could have matched, thus we need to remove
|
||||
// duplicates.
|
||||
|
@ -1729,18 +1721,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
referenced_in.sort_unstable();
|
||||
referenced_in.dedup();
|
||||
|
||||
if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
|
||||
if let &[idx] = &referenced_in[..] {
|
||||
// Do not point at the inside of a macro.
|
||||
// That would often result in poor error messages.
|
||||
if args[ref_in].span.from_expansion() {
|
||||
return;
|
||||
if args[idx].span.from_expansion() {
|
||||
continue;
|
||||
}
|
||||
// We make sure that only *one* argument matches the obligation failure
|
||||
// and we assign the obligation's span to its expression's.
|
||||
error.obligation.cause.span = args[ref_in].span;
|
||||
error.obligation.cause.span = args[idx].span;
|
||||
error.obligation.cause.map_code(|parent_code| {
|
||||
ObligationCauseCode::FunctionArgumentObligation {
|
||||
arg_hir_id: args[ref_in].hir_id,
|
||||
arg_hir_id: args[idx].hir_id,
|
||||
call_hir_id: expr.hir_id,
|
||||
parent_code,
|
||||
}
|
||||
|
|
|
@ -231,7 +231,8 @@ impl fmt::Debug for c_void {
|
|||
all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
|
||||
target_family = "wasm",
|
||||
target_arch = "asmjs",
|
||||
windows
|
||||
target_os = "uefi",
|
||||
windows,
|
||||
))]
|
||||
#[repr(transparent)]
|
||||
#[unstable(
|
||||
|
@ -254,7 +255,8 @@ pub struct VaListImpl<'f> {
|
|||
all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
|
||||
target_family = "wasm",
|
||||
target_arch = "asmjs",
|
||||
windows
|
||||
target_os = "uefi",
|
||||
windows,
|
||||
))]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
|
@ -276,7 +278,8 @@ impl<'f> fmt::Debug for VaListImpl<'f> {
|
|||
#[cfg(all(
|
||||
target_arch = "aarch64",
|
||||
not(any(target_os = "macos", target_os = "ios")),
|
||||
not(windows)
|
||||
not(target_os = "uefi"),
|
||||
not(windows),
|
||||
))]
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
|
@ -297,7 +300,7 @@ pub struct VaListImpl<'f> {
|
|||
}
|
||||
|
||||
/// PowerPC ABI implementation of a `va_list`.
|
||||
#[cfg(all(target_arch = "powerpc", not(windows)))]
|
||||
#[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))]
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[unstable(
|
||||
|
@ -317,7 +320,7 @@ pub struct VaListImpl<'f> {
|
|||
}
|
||||
|
||||
/// x86_64 ABI implementation of a `va_list`.
|
||||
#[cfg(all(target_arch = "x86_64", not(windows)))]
|
||||
#[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))]
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
#[unstable(
|
||||
|
@ -354,7 +357,8 @@ pub struct VaList<'a, 'f: 'a> {
|
|||
all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
|
||||
target_family = "wasm",
|
||||
target_arch = "asmjs",
|
||||
windows
|
||||
target_os = "uefi",
|
||||
windows,
|
||||
))]
|
||||
inner: VaListImpl<'f>,
|
||||
|
||||
|
@ -363,7 +367,8 @@ pub struct VaList<'a, 'f: 'a> {
|
|||
any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
|
||||
not(target_family = "wasm"),
|
||||
not(target_arch = "asmjs"),
|
||||
not(windows)
|
||||
not(target_os = "uefi"),
|
||||
not(windows),
|
||||
))]
|
||||
inner: &'a mut VaListImpl<'f>,
|
||||
|
||||
|
@ -375,7 +380,8 @@ pub struct VaList<'a, 'f: 'a> {
|
|||
all(target_arch = "aarch64", any(target_os = "macos", target_os = "ios")),
|
||||
target_family = "wasm",
|
||||
target_arch = "asmjs",
|
||||
windows
|
||||
target_os = "uefi",
|
||||
windows,
|
||||
))]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
|
@ -396,7 +402,8 @@ impl<'f> VaListImpl<'f> {
|
|||
any(not(target_arch = "aarch64"), not(any(target_os = "macos", target_os = "ios"))),
|
||||
not(target_family = "wasm"),
|
||||
not(target_arch = "asmjs"),
|
||||
not(windows)
|
||||
not(target_os = "uefi"),
|
||||
not(windows),
|
||||
))]
|
||||
#[unstable(
|
||||
feature = "c_variadic",
|
||||
|
|
|
@ -854,6 +854,42 @@ impl AtomicBool {
|
|||
unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
|
||||
}
|
||||
|
||||
/// Logical "not" with a boolean value.
|
||||
///
|
||||
/// Performs a logical "not" operation on the current value, and sets
|
||||
/// the new value to the result.
|
||||
///
|
||||
/// Returns the previous value.
|
||||
///
|
||||
/// `fetch_not` takes an [`Ordering`] argument which describes the memory ordering
|
||||
/// of this operation. All ordering modes are possible. Note that using
|
||||
/// [`Acquire`] makes the store part of this operation [`Relaxed`], and
|
||||
/// using [`Release`] makes the load part [`Relaxed`].
|
||||
///
|
||||
/// **Note:** This method is only available on platforms that support atomic
|
||||
/// operations on `u8`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(atomic_bool_fetch_not)]
|
||||
/// use std::sync::atomic::{AtomicBool, Ordering};
|
||||
///
|
||||
/// let foo = AtomicBool::new(true);
|
||||
/// assert_eq!(foo.fetch_not(Ordering::SeqCst), true);
|
||||
/// assert_eq!(foo.load(Ordering::SeqCst), false);
|
||||
///
|
||||
/// let foo = AtomicBool::new(false);
|
||||
/// assert_eq!(foo.fetch_not(Ordering::SeqCst), false);
|
||||
/// assert_eq!(foo.load(Ordering::SeqCst), true);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "atomic_bool_fetch_not", issue = "98485")]
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
pub fn fetch_not(&self, order: Ordering) -> bool {
|
||||
self.fetch_xor(true, order)
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer to the underlying [`bool`].
|
||||
///
|
||||
/// Doing non-atomic reads and writes on the resulting integer can be a data race.
|
||||
|
|
|
@ -129,6 +129,7 @@ fn array_casts() -> () {
|
|||
_18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_13 = (move _14, move _18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
Retag(_13); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
StorageDead(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
StorageDead(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
StorageLive(_20); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
|
@ -171,6 +172,7 @@ fn array_casts() -> () {
|
|||
Retag(_32); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
StorageLive(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_34 = Option::<Arguments>::None; // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
Retag(_34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
_28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
// mir::Constant
|
||||
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
|
||||
|
|
33
src/test/ui/const-generics/try_unify_ignore_lifetimes.rs
Normal file
33
src/test/ui/const-generics/try_unify_ignore_lifetimes.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// check-pass
|
||||
#![feature(generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Num<const N: usize>;
|
||||
|
||||
trait NumT {
|
||||
const VALUE: usize;
|
||||
}
|
||||
|
||||
impl<const N: usize> NumT for Num<N> {
|
||||
const VALUE: usize = N;
|
||||
}
|
||||
|
||||
struct Foo<'a, N: NumT>(&'a [u32; N::VALUE]) where [(); N::VALUE]:;
|
||||
|
||||
trait Bar {
|
||||
type Size: NumT;
|
||||
|
||||
fn bar<'a>(foo: &Foo<'a, Self::Size>) where [(); Self::Size::VALUE]: {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
trait Baz<'a> {
|
||||
type Size: NumT;
|
||||
|
||||
fn baz(foo: &Foo<'a, Self::Size>) where [(); Self::Size::VALUE]: {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,14 +1,14 @@
|
|||
error[E0161]: cannot move a value of type str: the size of str cannot be statically determined
|
||||
error[E0161]: cannot move a value of type `str`
|
||||
--> $DIR/dst-index.rs:31:5
|
||||
|
|
||||
LL | S[0];
|
||||
| ^^^^
|
||||
| ^^^^ the size of `str` cannot be statically determined
|
||||
|
||||
error[E0161]: cannot move a value of type dyn Debug: the size of dyn Debug cannot be statically determined
|
||||
error[E0161]: cannot move a value of type `dyn Debug`
|
||||
--> $DIR/dst-index.rs:34:5
|
||||
|
|
||||
LL | T[0];
|
||||
| ^^^^
|
||||
| ^^^^ the size of `dyn Debug` cannot be statically determined
|
||||
|
||||
error[E0507]: cannot move out of index of `S`
|
||||
--> $DIR/dst-index.rs:31:5
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
|
||||
error[E0161]: cannot move a value of type `dyn Bar`
|
||||
--> $DIR/E0161.rs:16:5
|
||||
|
|
||||
LL | x.f();
|
||||
| ^^^^^
|
||||
| ^^^^^ the size of `dyn Bar` cannot be statically determined
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ error: higher-ranked lifetime error
|
|||
LL | v.t(|| {});
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed
|
||||
= note: could not prove `[closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed`
|
||||
|
||||
error: higher-ranked lifetime error
|
||||
--> $DIR/issue-59311.rs:17:9
|
||||
|
@ -12,7 +12,7 @@ error: higher-ranked lifetime error
|
|||
LL | v.t(|| {});
|
||||
| ^^^^^
|
||||
|
|
||||
= note: could not prove for<'a> &'a V: 'static
|
||||
= note: could not prove `for<'a> &'a V: 'static`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ error: higher-ranked lifetime error
|
|||
LL | foo(&10);
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: could not prove for<'b, 'r> &'b (): 'r
|
||||
= note: could not prove `for<'b, 'r> &'b (): 'r`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
struct Bug {
|
||||
A: [(); { *"" }.len()],
|
||||
//~^ ERROR: cannot move a value of type str
|
||||
//~^ ERROR: cannot move a value of type `str`
|
||||
//~| ERROR: cannot move out of a shared reference
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0161]: cannot move a value of type str: the size of str cannot be statically determined
|
||||
error[E0161]: cannot move a value of type `str`
|
||||
--> $DIR/issue-67947.rs:2:13
|
||||
|
|
||||
LL | A: [(); { *"" }.len()],
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the size of `str` cannot be statically determined
|
||||
|
||||
error[E0507]: cannot move out of a shared reference
|
||||
--> $DIR/issue-67947.rs:2:15
|
||||
|
|
|
@ -12,7 +12,7 @@ trait Baz {
|
|||
}
|
||||
|
||||
fn use_bar(t: Box<dyn Bar>) {
|
||||
t.bar() //~ ERROR cannot move a value of type dyn Bar
|
||||
t.bar() //~ ERROR cannot move a value of type `dyn Bar`
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0161]: cannot move a value of type dyn Bar: the size of dyn Bar cannot be statically determined
|
||||
error[E0161]: cannot move a value of type `dyn Bar`
|
||||
--> $DIR/object-safety-by-value-self-use.rs:15:5
|
||||
|
|
||||
LL | t.bar()
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the size of `dyn Bar` cannot be statically determined
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -5,10 +5,7 @@ LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
|||
LL | |
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| | ^
|
||||
| | |
|
||||
| |_call the function in a closure: `|| unsafe { /* code */ }`
|
||||
| required by a bound introduced by this call
|
||||
| |_^ call the function in a closure: `|| unsafe { /* code */ }`
|
||||
|
|
||||
= help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
|
||||
= note: unsafe function cannot be called generically without an unsafe block
|
||||
|
|
|
@ -9,7 +9,7 @@ note: tuple variant defined here
|
|||
|
|
||||
LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
|
||||
| ^^
|
||||
help: use parentheses to construct a tuple
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | let _: Result<(i32, i8), ()> = Ok((1, 2));
|
||||
| + +
|
||||
|
@ -25,7 +25,7 @@ note: tuple variant defined here
|
|||
|
|
||||
LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T),
|
||||
| ^^^^
|
||||
help: use parentheses to construct a tuple
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
|
||||
| + +
|
||||
|
@ -97,7 +97,7 @@ note: function defined here
|
|||
|
|
||||
LL | fn two_ints(_: (i32, i32)) {
|
||||
| ^^^^^^^^ -------------
|
||||
help: use parentheses to construct a tuple
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | two_ints((1, 2));
|
||||
| + +
|
||||
|
@ -113,7 +113,7 @@ note: function defined here
|
|||
|
|
||||
LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
|
||||
| ^^^^^^^^^^^^ ----------------
|
||||
help: use parentheses to construct a tuple
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | with_generic((3, 4));
|
||||
| + +
|
||||
|
@ -129,7 +129,7 @@ note: function defined here
|
|||
|
|
||||
LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
|
||||
| ^^^^^^^^^^^^ ----------------
|
||||
help: use parentheses to construct a tuple
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | with_generic((a, b));
|
||||
| + +
|
||||
|
|
10
src/test/ui/tuple/add-tuple-within-arguments.rs
Normal file
10
src/test/ui/tuple/add-tuple-within-arguments.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
fn foo(s: &str, a: (i32, i32), s2: &str) {}
|
||||
|
||||
fn bar(s: &str, a: (&str,), s2: &str) {}
|
||||
|
||||
fn main() {
|
||||
foo("hi", 1, 2, "hi");
|
||||
//~^ ERROR this function takes 3 arguments but 4 arguments were supplied
|
||||
bar("hi", "hi", "hi");
|
||||
//~^ ERROR mismatched types
|
||||
}
|
40
src/test/ui/tuple/add-tuple-within-arguments.stderr
Normal file
40
src/test/ui/tuple/add-tuple-within-arguments.stderr
Normal file
|
@ -0,0 +1,40 @@
|
|||
error[E0061]: this function takes 3 arguments but 4 arguments were supplied
|
||||
--> $DIR/add-tuple-within-arguments.rs:6:5
|
||||
|
|
||||
LL | foo("hi", 1, 2, "hi");
|
||||
| ^^^
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/add-tuple-within-arguments.rs:1:4
|
||||
|
|
||||
LL | fn foo(s: &str, a: (i32, i32), s2: &str) {}
|
||||
| ^^^ ------- ------------- --------
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | foo("hi", (1, 2), "hi");
|
||||
| + +
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/add-tuple-within-arguments.rs:8:15
|
||||
|
|
||||
LL | bar("hi", "hi", "hi");
|
||||
| --- ^^^^ expected tuple, found `&str`
|
||||
| |
|
||||
| arguments to this function are incorrect
|
||||
|
|
||||
= note: expected tuple `(&str,)`
|
||||
found reference `&'static str`
|
||||
note: function defined here
|
||||
--> $DIR/add-tuple-within-arguments.rs:3:4
|
||||
|
|
||||
LL | fn bar(s: &str, a: (&str,), s2: &str) {}
|
||||
| ^^^ ------- ---------- --------
|
||||
help: use a trailing comma to create a tuple with one element
|
||||
|
|
||||
LL | bar("hi", ("hi",), "hi");
|
||||
| + ++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0061, E0308.
|
||||
For more information about an error, try `rustc --explain E0061`.
|
|
@ -9,7 +9,7 @@ note: function defined here
|
|||
|
|
||||
LL | fn test(t: (i32, i32)) {}
|
||||
| ^^^^ -------------
|
||||
help: use parentheses to construct a tuple
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | test((x.qux(), x.qux()));
|
||||
| + +
|
||||
|
|
|
@ -9,7 +9,7 @@ note: associated function defined here
|
|||
|
|
||||
LL | pub fn push_back(&mut self, value: T) {
|
||||
| ^^^^^^^^^
|
||||
help: use parentheses to construct a tuple
|
||||
help: wrap these arguments in parentheses to construct a tuple
|
||||
|
|
||||
LL | self.acc.push_back((self.current_provides, self.current_requires));
|
||||
| + +
|
||||
|
|
|
@ -7,7 +7,7 @@ trait Foo {
|
|||
fn foo(f: Option<&dyn Foo>) {
|
||||
if let Some(f) = f {
|
||||
let _ = f.foo();
|
||||
//~^ ERROR cannot move a value of type [u8]: the size of [u8] cannot be statically determined
|
||||
//~^ ERROR cannot move a value of type `[u8]`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error[E0161]: cannot move a value of type [u8]: the size of [u8] cannot be statically determined
|
||||
error[E0161]: cannot move a value of type `[u8]`
|
||||
--> $DIR/return-unsized-from-trait-method.rs:9:17
|
||||
|
|
||||
LL | let _ = f.foo();
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^ the size of `[u8]` cannot be statically determined
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -2,7 +2,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
|
|||
--> $DIR/unsized-fn-param.rs:11:11
|
||||
|
|
||||
LL | foo11("bar", &"baz");
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
| ----- ^^^^^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast from `str` to the object type `dyn AsRef<Path>`
|
||||
|
@ -15,7 +17,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
|
|||
--> $DIR/unsized-fn-param.rs:13:19
|
||||
|
|
||||
LL | foo12(&"bar", "baz");
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
| ----- ^^^^^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast from `str` to the object type `dyn AsRef<Path>`
|
||||
|
@ -28,7 +32,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
|
|||
--> $DIR/unsized-fn-param.rs:16:11
|
||||
|
|
||||
LL | foo21("bar", &"baz");
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
| ----- ^^^^^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast from `str` to the object type `dyn AsRef<str>`
|
||||
|
@ -41,7 +47,9 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
|
|||
--> $DIR/unsized-fn-param.rs:18:19
|
||||
|
|
||||
LL | foo22(&"bar", "baz");
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
| ----- ^^^^^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Sized` is not implemented for `str`
|
||||
= note: required for the cast from `str` to the object type `dyn AsRef<str>`
|
||||
|
|
|
@ -44,6 +44,7 @@ fn f9<X: ?Sized>(x1: Box<S<X>>) {
|
|||
fn f10<X: ?Sized>(x1: Box<S<X>>) {
|
||||
f5(&(32, *x1));
|
||||
//~^ ERROR the size for values of type
|
||||
//~| ERROR the size for values of type
|
||||
}
|
||||
|
||||
pub fn main() {}
|
||||
|
|
|
@ -101,12 +101,12 @@ LL + fn f9<X>(x1: Box<S<X>>) {
|
|||
|
|
||||
|
||||
error[E0277]: the size for values of type `X` cannot be known at compilation time
|
||||
--> $DIR/unsized3.rs:45:8
|
||||
--> $DIR/unsized3.rs:45:9
|
||||
|
|
||||
LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
|
||||
| - this type parameter needs to be `std::marker::Sized`
|
||||
LL | f5(&(32, *x1));
|
||||
| -- ^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
| -- ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
|
@ -123,6 +123,37 @@ LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
|
|||
LL + fn f10<X>(x1: Box<S<X>>) {
|
||||
|
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error[E0277]: the size for values of type `X` cannot be known at compilation time
|
||||
--> $DIR/unsized3.rs:45:8
|
||||
|
|
||||
LL | fn f10<X: ?Sized>(x1: Box<S<X>>) {
|
||||
| - this type parameter needs to be `std::marker::Sized`
|
||||
LL | f5(&(32, *x1));
|
||||
| -- ^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
note: required because it appears within the type `S<X>`
|
||||
--> $DIR/unsized3.rs:28:8
|
||||
|
|
||||
LL | struct S<X: ?Sized> {
|
||||
| ^
|
||||
= note: required because it appears within the type `({integer}, S<X>)`
|
||||
note: required by a bound in `f5`
|
||||
--> $DIR/unsized3.rs:24:7
|
||||
|
|
||||
LL | fn f5<Y>(x: &Y) {}
|
||||
| ^ required by this bound in `f5`
|
||||
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||
|
|
||||
LL - fn f10<X: ?Sized>(x1: Box<S<X>>) {
|
||||
LL + fn f10<X>(x1: Box<S<X>>) {
|
||||
|
|
||||
help: consider relaxing the implicit `Sized` restriction
|
||||
|
|
||||
LL | fn f5<Y: ?Sized>(x: &Y) {}
|
||||
| ++++++++
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue