1
Fork 0

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:
bors 2022-06-29 15:05:29 +00:00
commit 3fcf43bb0f
39 changed files with 512 additions and 272 deletions

View file

@ -3595,6 +3595,7 @@ dependencies = [
"rustc_index",
"rustc_infer",
"rustc_lexer",
"rustc_macros",
"rustc_middle",
"rustc_mir_dataflow",
"rustc_serialize",

View file

@ -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" }

View file

@ -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 {

View file

@ -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,
},
));
}
}

View file

@ -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;

View 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,
}

View file

@ -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 });
}
}
}

View file

@ -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>`

View file

@ -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) => {

View 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

View file

@ -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};

View file

@ -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![];

View file

@ -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,
}

View file

@ -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>| {

View file

@ -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));
}
}
}

View file

@ -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,
}

View file

@ -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",

View file

@ -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.

View file

@ -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

View 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() {}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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() { }

View file

@ -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

View file

@ -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

View file

@ -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));
| + +

View 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
}

View 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`.

View file

@ -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()));
| + +

View file

@ -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));
| + +

View file

@ -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]`
}
}

View file

@ -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

View file

@ -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>`

View file

@ -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() {}

View file

@ -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`.