mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #120980 - matthiaskrgr:rollup-dsjsqql, r=matthiaskrgr
Rollup of 11 pull requests Successful merges: - #120765 (Reorder diagnostics API) - #120833 (More internal emit diagnostics cleanups) - #120899 (Gracefully handle non-WF alias in `assemble_alias_bound_candidates_recur`) - #120917 (Remove a bunch of dead parameters in functions) - #120928 (Add test for recently fixed issue) - #120933 (check_consts: fix duplicate errors, make importance consistent) - #120936 (improve `btree_cursors` functions documentation) - #120944 (Check that the ABI of the instance we are inlining is correct) - #120956 (Clean inlined type alias with correct param-env) - #120962 (Add myself to library/std review) - #120972 (fix ICE for deref coercions with type errors) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b381d3ab27
@ -3018,7 +3018,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
/// assignment to `x.f`).
|
||||
pub(crate) fn report_illegal_reassignment(
|
||||
&mut self,
|
||||
_location: Location,
|
||||
(place, span): (Place<'tcx>, Span),
|
||||
assigned_span: Span,
|
||||
err_place: Place<'tcx>,
|
||||
|
@ -1036,7 +1036,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self,
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
location,
|
||||
(sd, place_span.0),
|
||||
&borrow_set,
|
||||
|borrow_index| borrows_in_scope.contains(borrow_index),
|
||||
@ -2174,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
// report the error as an illegal reassignment
|
||||
let init = &self.move_data.inits[init_index];
|
||||
let assigned_span = init.span(self.body);
|
||||
self.report_illegal_reassignment(location, (place, span), assigned_span, place);
|
||||
self.report_illegal_reassignment((place, span), assigned_span, place);
|
||||
} else {
|
||||
self.report_mutability_error(place, span, the_place_err, error_access, location)
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
||||
s: &mut S,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
_location: Location,
|
||||
access_place: (AccessDepth, Place<'tcx>),
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
is_candidate: I,
|
||||
|
@ -340,7 +340,6 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
||||
self,
|
||||
self.tcx,
|
||||
self.body,
|
||||
location,
|
||||
(sd, place),
|
||||
self.borrow_set,
|
||||
|_| true,
|
||||
|
@ -662,7 +662,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
|
||||
let mir_def_id = body.source.def_id();
|
||||
self.propagate_constraints(body);
|
||||
self.propagate_constraints();
|
||||
|
||||
let mut errors_buffer = RegionErrors::new(infcx.tcx);
|
||||
|
||||
@ -716,8 +716,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// for each region variable until all the constraints are
|
||||
/// satisfied. Note that some values may grow **too** large to be
|
||||
/// feasible, but we check this later.
|
||||
#[instrument(skip(self, _body), level = "debug")]
|
||||
fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn propagate_constraints(&mut self) {
|
||||
debug!("constraints={:#?}", {
|
||||
let mut constraints: Vec<_> = self.outlives_constraints().collect();
|
||||
constraints.sort_by_key(|c| (c.sup, c.sub));
|
||||
|
@ -151,7 +151,7 @@ where
|
||||
let mut err = tcx.dcx().create_err(err);
|
||||
|
||||
let msg = error.diagnostic_message();
|
||||
error.add_args(tcx.dcx(), &mut err);
|
||||
error.add_args(&mut err);
|
||||
|
||||
// Use *our* span to label the interp error
|
||||
err.span_label(our_span, msg);
|
||||
|
@ -426,7 +426,7 @@ pub struct UndefinedBehavior {
|
||||
pub trait ReportErrorExt {
|
||||
/// Returns the diagnostic message for this error.
|
||||
fn diagnostic_message(&self) -> DiagnosticMessage;
|
||||
fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>);
|
||||
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>);
|
||||
|
||||
fn debug(self) -> String
|
||||
where
|
||||
@ -434,11 +434,11 @@ pub trait ReportErrorExt {
|
||||
{
|
||||
ty::tls::with(move |tcx| {
|
||||
let dcx = tcx.dcx();
|
||||
let mut builder = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
|
||||
let mut diag = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
|
||||
let message = self.diagnostic_message();
|
||||
self.add_args(dcx, &mut builder);
|
||||
let s = dcx.eagerly_translate_to_string(message, builder.args());
|
||||
builder.cancel();
|
||||
self.add_args(&mut diag);
|
||||
let s = dcx.eagerly_translate_to_string(message, diag.args());
|
||||
diag.cancel();
|
||||
s
|
||||
})
|
||||
}
|
||||
@ -505,20 +505,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_args<G: EmissionGuarantee>(
|
||||
self,
|
||||
dcx: &DiagCtxt,
|
||||
builder: &mut DiagnosticBuilder<'_, G>,
|
||||
) {
|
||||
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||
use UndefinedBehaviorInfo::*;
|
||||
let dcx = diag.dcx;
|
||||
match self {
|
||||
Ub(_) => {}
|
||||
Custom(custom) => {
|
||||
(custom.add_args)(&mut |name, value| {
|
||||
builder.arg(name, value);
|
||||
diag.arg(name, value);
|
||||
});
|
||||
}
|
||||
ValidationError(e) => e.add_args(dcx, builder),
|
||||
ValidationError(e) => e.add_args(diag),
|
||||
|
||||
Unreachable
|
||||
| DivisionByZero
|
||||
@ -533,20 +530,18 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||
| UninhabitedEnumVariantWritten(_)
|
||||
| UninhabitedEnumVariantRead(_) => {}
|
||||
BoundsCheckFailed { len, index } => {
|
||||
builder.arg("len", len);
|
||||
builder.arg("index", index);
|
||||
diag.arg("len", len);
|
||||
diag.arg("index", index);
|
||||
}
|
||||
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
|
||||
builder.arg("pointer", ptr);
|
||||
diag.arg("pointer", ptr);
|
||||
}
|
||||
PointerUseAfterFree(alloc_id, msg) => {
|
||||
builder
|
||||
.arg("alloc_id", alloc_id)
|
||||
diag.arg("alloc_id", alloc_id)
|
||||
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
||||
}
|
||||
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
|
||||
builder
|
||||
.arg("alloc_id", alloc_id)
|
||||
diag.arg("alloc_id", alloc_id)
|
||||
.arg("alloc_size", alloc_size.bytes())
|
||||
.arg("ptr_offset", ptr_offset)
|
||||
.arg("ptr_size", ptr_size.bytes())
|
||||
@ -554,47 +549,47 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
|
||||
}
|
||||
DanglingIntPointer(ptr, msg) => {
|
||||
if ptr != 0 {
|
||||
builder.arg("pointer", format!("{ptr:#x}[noalloc]"));
|
||||
diag.arg("pointer", format!("{ptr:#x}[noalloc]"));
|
||||
}
|
||||
|
||||
builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
||||
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
|
||||
}
|
||||
AlignmentCheckFailed(Misalignment { required, has }, msg) => {
|
||||
builder.arg("required", required.bytes());
|
||||
builder.arg("has", has.bytes());
|
||||
builder.arg("msg", format!("{msg:?}"));
|
||||
diag.arg("required", required.bytes());
|
||||
diag.arg("has", has.bytes());
|
||||
diag.arg("msg", format!("{msg:?}"));
|
||||
}
|
||||
WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
|
||||
builder.arg("allocation", alloc);
|
||||
diag.arg("allocation", alloc);
|
||||
}
|
||||
InvalidBool(b) => {
|
||||
builder.arg("value", format!("{b:02x}"));
|
||||
diag.arg("value", format!("{b:02x}"));
|
||||
}
|
||||
InvalidChar(c) => {
|
||||
builder.arg("value", format!("{c:08x}"));
|
||||
diag.arg("value", format!("{c:08x}"));
|
||||
}
|
||||
InvalidTag(tag) => {
|
||||
builder.arg("tag", format!("{tag:x}"));
|
||||
diag.arg("tag", format!("{tag:x}"));
|
||||
}
|
||||
InvalidStr(err) => {
|
||||
builder.arg("err", format!("{err}"));
|
||||
diag.arg("err", format!("{err}"));
|
||||
}
|
||||
InvalidUninitBytes(Some((alloc, info))) => {
|
||||
builder.arg("alloc", alloc);
|
||||
builder.arg("access", info.access);
|
||||
builder.arg("uninit", info.bad);
|
||||
diag.arg("alloc", alloc);
|
||||
diag.arg("access", info.access);
|
||||
diag.arg("uninit", info.bad);
|
||||
}
|
||||
ScalarSizeMismatch(info) => {
|
||||
builder.arg("target_size", info.target_size);
|
||||
builder.arg("data_size", info.data_size);
|
||||
diag.arg("target_size", info.target_size);
|
||||
diag.arg("data_size", info.data_size);
|
||||
}
|
||||
InvalidNichedEnumVariantWritten { enum_ty } => {
|
||||
builder.arg("ty", enum_ty.to_string());
|
||||
diag.arg("ty", enum_ty.to_string());
|
||||
}
|
||||
AbiMismatchArgument { caller_ty, callee_ty }
|
||||
| AbiMismatchReturn { caller_ty, callee_ty } => {
|
||||
builder.arg("caller_ty", caller_ty.to_string());
|
||||
builder.arg("callee_ty", callee_ty.to_string());
|
||||
diag.arg("caller_ty", caller_ty.to_string());
|
||||
diag.arg("callee_ty", callee_ty.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -674,7 +669,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) {
|
||||
fn add_args<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
|
||||
use crate::fluent_generated as fluent;
|
||||
use rustc_middle::mir::interpret::ValidationErrorKind::*;
|
||||
|
||||
@ -684,12 +679,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||
}
|
||||
|
||||
let message = if let Some(path) = self.path {
|
||||
dcx.eagerly_translate_to_string(
|
||||
err.dcx.eagerly_translate_to_string(
|
||||
fluent::const_eval_validation_front_matter_invalid_value_with_path,
|
||||
[("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
|
||||
)
|
||||
} else {
|
||||
dcx.eagerly_translate_to_string(
|
||||
err.dcx.eagerly_translate_to_string(
|
||||
fluent::const_eval_validation_front_matter_invalid_value,
|
||||
[].into_iter(),
|
||||
)
|
||||
@ -700,7 +695,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||
fn add_range_arg<G: EmissionGuarantee>(
|
||||
r: WrappingRange,
|
||||
max_hi: u128,
|
||||
dcx: &DiagCtxt,
|
||||
err: &mut DiagnosticBuilder<'_, G>,
|
||||
) {
|
||||
let WrappingRange { start: lo, end: hi } = r;
|
||||
@ -724,7 +718,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||
("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
|
||||
];
|
||||
let args = args.iter().map(|(a, b)| (a, b));
|
||||
let message = dcx.eagerly_translate_to_string(msg, args);
|
||||
let message = err.dcx.eagerly_translate_to_string(msg, args);
|
||||
err.arg("in_range", message);
|
||||
}
|
||||
|
||||
@ -746,7 +740,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||
ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
|
||||
ExpectedKind::Str => fluent::const_eval_validation_expected_str,
|
||||
};
|
||||
let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
|
||||
let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
|
||||
err.arg("expected", msg);
|
||||
}
|
||||
InvalidEnumTag { value }
|
||||
@ -757,11 +751,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
|
||||
err.arg("value", value);
|
||||
}
|
||||
NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
|
||||
add_range_arg(range, max_value, dcx, err)
|
||||
add_range_arg(range, max_value, err)
|
||||
}
|
||||
OutOfRange { range, max_value, value } => {
|
||||
err.arg("value", value);
|
||||
add_range_arg(range, max_value, dcx, err);
|
||||
add_range_arg(range, max_value, err);
|
||||
}
|
||||
UnalignedPtr { required_bytes, found_bytes, .. } => {
|
||||
err.arg("required_bytes", required_bytes);
|
||||
@ -802,13 +796,13 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
||||
UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
|
||||
}
|
||||
}
|
||||
fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
|
||||
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||
use crate::fluent_generated::*;
|
||||
|
||||
use UnsupportedOpInfo::*;
|
||||
if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
|
||||
builder.help(const_eval_ptr_as_bytes_1);
|
||||
builder.help(const_eval_ptr_as_bytes_2);
|
||||
diag.help(const_eval_ptr_as_bytes_1);
|
||||
diag.help(const_eval_ptr_as_bytes_2);
|
||||
}
|
||||
match self {
|
||||
// `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
|
||||
@ -816,10 +810,10 @@ impl ReportErrorExt for UnsupportedOpInfo {
|
||||
// print. So it's not worth the effort of having diagnostics that can print the `info`.
|
||||
UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
|
||||
OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
|
||||
builder.arg("ptr", ptr);
|
||||
diag.arg("ptr", ptr);
|
||||
}
|
||||
ThreadLocalStatic(did) | ExternStatic(did) => {
|
||||
builder.arg("did", format!("{did:?}"));
|
||||
diag.arg("did", format!("{did:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -835,18 +829,14 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> {
|
||||
InterpError::MachineStop(e) => e.diagnostic_message(),
|
||||
}
|
||||
}
|
||||
fn add_args<G: EmissionGuarantee>(
|
||||
self,
|
||||
dcx: &DiagCtxt,
|
||||
builder: &mut DiagnosticBuilder<'_, G>,
|
||||
) {
|
||||
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||
match self {
|
||||
InterpError::UndefinedBehavior(ub) => ub.add_args(dcx, builder),
|
||||
InterpError::Unsupported(e) => e.add_args(dcx, builder),
|
||||
InterpError::InvalidProgram(e) => e.add_args(dcx, builder),
|
||||
InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder),
|
||||
InterpError::UndefinedBehavior(ub) => ub.add_args(diag),
|
||||
InterpError::Unsupported(e) => e.add_args(diag),
|
||||
InterpError::InvalidProgram(e) => e.add_args(diag),
|
||||
InterpError::ResourceExhaustion(e) => e.add_args(diag),
|
||||
InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
|
||||
builder.arg(name, value);
|
||||
diag.arg(name, value);
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -864,28 +854,24 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn add_args<G: EmissionGuarantee>(
|
||||
self,
|
||||
dcx: &DiagCtxt,
|
||||
builder: &mut DiagnosticBuilder<'_, G>,
|
||||
) {
|
||||
fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
|
||||
match self {
|
||||
InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
|
||||
InvalidProgramInfo::Layout(e) => {
|
||||
// The level doesn't matter, `diag` is consumed without it being used.
|
||||
// The level doesn't matter, `dummy_diag` is consumed without it being used.
|
||||
let dummy_level = Level::Bug;
|
||||
let diag: DiagnosticBuilder<'_, ()> =
|
||||
e.into_diagnostic().into_diagnostic(dcx, dummy_level);
|
||||
for (name, val) in diag.args() {
|
||||
builder.arg(name.clone(), val.clone());
|
||||
let dummy_diag: DiagnosticBuilder<'_, ()> =
|
||||
e.into_diagnostic().into_diagnostic(diag.dcx, dummy_level);
|
||||
for (name, val) in dummy_diag.args() {
|
||||
diag.arg(name.clone(), val.clone());
|
||||
}
|
||||
diag.cancel();
|
||||
dummy_diag.cancel();
|
||||
}
|
||||
InvalidProgramInfo::FnAbiAdjustForForeignAbi(
|
||||
AdjustForForeignAbiError::Unsupported { arch, abi },
|
||||
) => {
|
||||
builder.arg("arch", arch);
|
||||
builder.arg("abi", abi.name());
|
||||
diag.arg("arch", arch);
|
||||
diag.arg("abi", abi.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -900,7 +886,7 @@ impl ReportErrorExt for ResourceExhaustionInfo {
|
||||
ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
|
||||
}
|
||||
}
|
||||
fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
|
||||
fn add_args<G: EmissionGuarantee>(self, _: &mut DiagnosticBuilder<'_, G>) {}
|
||||
}
|
||||
|
||||
impl rustc_errors::IntoDiagnosticArg for InternKind {
|
||||
|
@ -445,7 +445,7 @@ pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> St
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
let mut diag = dcx.struct_allow("");
|
||||
let msg = e.diagnostic_message();
|
||||
e.add_args(dcx, &mut diag);
|
||||
e.add_args(&mut diag);
|
||||
let s = dcx.eagerly_translate_to_string(msg, diag.args());
|
||||
diag.cancel();
|
||||
s
|
||||
|
@ -619,9 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
if base_ty.is_unsafe_ptr() {
|
||||
if place_ref.projection.is_empty() {
|
||||
let decl = &self.body.local_decls[place_ref.local];
|
||||
if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
|
||||
let span = decl.source_info.span;
|
||||
self.check_static(def_id, span);
|
||||
// If this is a static, then this is not really dereferencing a pointer,
|
||||
// just directly accessing a static. That is not subject to any feature
|
||||
// gates (except for the one about whether statics can even be used, but
|
||||
// that is checked already by `visit_operand`).
|
||||
if let LocalInfo::StaticRef { .. } = *decl.local_info() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -409,11 +409,6 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
|
||||
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
|
||||
Status::Unstable(sym::const_refs_to_cell)
|
||||
}
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
// The cases that cannot possibly work will already emit a `CellBorrow`, so we should
|
||||
// not additionally emit a feature gate error if activating the feature gate won't work.
|
||||
DiagnosticImportance::Secondary
|
||||
}
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
ccx.tcx
|
||||
.sess
|
||||
@ -427,6 +422,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
|
||||
/// it in the future for static items.
|
||||
pub struct CellBorrow;
|
||||
impl<'tcx> NonConstOp<'tcx> for CellBorrow {
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
// Most likely the code will try to do mutation with these borrows, which
|
||||
// triggers its own errors. Only show this one if that does not happen.
|
||||
DiagnosticImportance::Secondary
|
||||
}
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
|
||||
// FIXME: Maybe a more elegant solution to this if else case
|
||||
if let hir::ConstContext::Static(_) = ccx.const_kind() {
|
||||
@ -459,8 +459,8 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
|
||||
}
|
||||
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
// If there were primary errors (like non-const function calls), do not emit further
|
||||
// errors about mutable references.
|
||||
// Most likely the code will try to do mutation with these borrows, which
|
||||
// triggers its own errors. Only show this one if that does not happen.
|
||||
DiagnosticImportance::Secondary
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
|
||||
fn address_of_allows_mutation(&self) -> bool {
|
||||
// Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
|
||||
// it might allow mutation until resolution of #56604.
|
||||
true
|
||||
@ -171,10 +171,8 @@ where
|
||||
self.super_rvalue(rvalue, location);
|
||||
|
||||
match rvalue {
|
||||
mir::Rvalue::AddressOf(mt, borrowed_place) => {
|
||||
if !borrowed_place.is_indirect()
|
||||
&& self.address_of_allows_mutation(*mt, *borrowed_place)
|
||||
{
|
||||
mir::Rvalue::AddressOf(_mt, borrowed_place) => {
|
||||
if !borrowed_place.is_indirect() && self.address_of_allows_mutation() {
|
||||
let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
|
||||
if Q::in_any_value_of_ty(self.ccx, place_ty) {
|
||||
self.state.qualif.insert(borrowed_place.local);
|
||||
|
@ -411,8 +411,8 @@ impl CodeSuggestion {
|
||||
/// or `.span_bug` rather than a failed assertion, etc.
|
||||
pub struct ExplicitBug;
|
||||
|
||||
/// Signifies that the compiler died with an explicit call to `.delay_*_bug`
|
||||
/// rather than a failed assertion, etc.
|
||||
/// Signifies that the compiler died due to a delayed bug rather than a failed
|
||||
/// assertion, etc.
|
||||
pub struct DelayedBugPanic;
|
||||
|
||||
/// A `DiagCtxt` deals with errors and other compiler output.
|
||||
@ -428,10 +428,14 @@ pub struct DiagCtxt {
|
||||
struct DiagCtxtInner {
|
||||
flags: DiagCtxtFlags,
|
||||
|
||||
/// The number of lint errors that have been emitted, including duplicates.
|
||||
lint_err_count: usize,
|
||||
/// The number of non-lint errors that have been emitted, including duplicates.
|
||||
err_count: usize,
|
||||
/// The error guarantees from all emitted errors. The length gives the error count.
|
||||
err_guars: Vec<ErrorGuaranteed>,
|
||||
/// The error guarantee from all emitted lint errors. The length gives the
|
||||
/// lint error count.
|
||||
lint_err_guars: Vec<ErrorGuaranteed>,
|
||||
/// The delayed bugs and their error guarantees.
|
||||
delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>,
|
||||
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
|
||||
|
||||
/// The number of stashed errors. Unlike the other counts, this can go up
|
||||
/// and down, so it doesn't guarantee anything.
|
||||
@ -447,8 +451,6 @@ struct DiagCtxtInner {
|
||||
has_printed: bool,
|
||||
|
||||
emitter: Box<DynEmitter>,
|
||||
delayed_bugs: Vec<DelayedDiagnostic>,
|
||||
good_path_delayed_bugs: Vec<DelayedDiagnostic>,
|
||||
/// This flag indicates that an expected diagnostic was emitted and suppressed.
|
||||
/// This is used for the `good_path_delayed_bugs` check.
|
||||
suppressed_expected_diag: bool,
|
||||
@ -560,7 +562,7 @@ impl Drop for DiagCtxtInner {
|
||||
fn drop(&mut self) {
|
||||
self.emit_stashed_diagnostics();
|
||||
|
||||
if !self.has_errors() {
|
||||
if self.err_guars.is_empty() {
|
||||
self.flush_delayed(DelayedBugKind::Normal)
|
||||
}
|
||||
|
||||
@ -604,15 +606,15 @@ impl DiagCtxt {
|
||||
Self {
|
||||
inner: Lock::new(DiagCtxtInner {
|
||||
flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
|
||||
lint_err_count: 0,
|
||||
err_count: 0,
|
||||
err_guars: Vec::new(),
|
||||
lint_err_guars: Vec::new(),
|
||||
delayed_bugs: Vec::new(),
|
||||
good_path_delayed_bugs: Vec::new(),
|
||||
stashed_err_count: 0,
|
||||
deduplicated_err_count: 0,
|
||||
deduplicated_warn_count: 0,
|
||||
has_printed: false,
|
||||
emitter,
|
||||
delayed_bugs: Vec::new(),
|
||||
good_path_delayed_bugs: Vec::new(),
|
||||
suppressed_expected_diag: false,
|
||||
taught_diagnostics: Default::default(),
|
||||
emitted_diagnostic_codes: Default::default(),
|
||||
@ -661,14 +663,14 @@ impl DiagCtxt {
|
||||
/// the overall count of emitted error diagnostics.
|
||||
pub fn reset_err_count(&self) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.lint_err_count = 0;
|
||||
inner.err_count = 0;
|
||||
inner.stashed_err_count = 0;
|
||||
inner.deduplicated_err_count = 0;
|
||||
inner.deduplicated_warn_count = 0;
|
||||
inner.has_printed = false;
|
||||
|
||||
// actually free the underlying memory (which `clear` would not do)
|
||||
inner.err_guars = Default::default();
|
||||
inner.lint_err_guars = Default::default();
|
||||
inner.delayed_bugs = Default::default();
|
||||
inner.good_path_delayed_bugs = Default::default();
|
||||
inner.taught_diagnostics = Default::default();
|
||||
@ -718,221 +720,10 @@ impl DiagCtxt {
|
||||
self.inner.borrow_mut().emit_stashed_diagnostics()
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
|
||||
///
|
||||
/// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_warn(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
self.struct_warn(msg).with_span(span)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Warning` level with the `msg`.
|
||||
///
|
||||
/// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Warning, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Allow` level with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Allow, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Expect` level with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_expect(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Expect(id), msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Error` level at the given `span` and with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_err(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.struct_err(msg).with_span(span)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Error` level with the `msg`.
|
||||
// FIXME: This method should be removed (every error should have an associated error code).
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
|
||||
DiagnosticBuilder::new(self, Error, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_fatal(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, FatalAbort> {
|
||||
self.struct_fatal(msg).with_span(span)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Fatal` level with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_fatal(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, FatalAbort> {
|
||||
DiagnosticBuilder::new(self, Fatal, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Help` level with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Help, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Note` level with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_note(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Note, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Bug` level with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_bug(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, BugAbort> {
|
||||
DiagnosticBuilder::new(self, Bug, msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Bug` level at the given `span` with the `msg`.
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_bug(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, BugAbort> {
|
||||
self.struct_bug(msg).with_span(span)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_span_fatal(span, msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_err(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.struct_span_err(span, msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_span_warn(span, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_span_bug(span, msg).emit()
|
||||
}
|
||||
|
||||
/// Ensures that compilation cannot succeed.
|
||||
///
|
||||
/// If this function has been called but no errors have been emitted and
|
||||
/// compilation succeeds, it will cause an internal compiler error (ICE).
|
||||
///
|
||||
/// This can be used in code paths that should never run on successful compilations.
|
||||
/// For example, it can be used to create an [`ErrorGuaranteed`]
|
||||
/// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission
|
||||
/// directly).
|
||||
#[track_caller]
|
||||
pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
|
||||
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
|
||||
}
|
||||
|
||||
/// Like `delayed_bug`, but takes an additional span.
|
||||
///
|
||||
/// Note: this function used to be called `delay_span_bug`. It was renamed
|
||||
/// to match similar functions like `span_err`, `span_warn`, etc.
|
||||
#[track_caller]
|
||||
pub fn span_delayed_bug(
|
||||
&self,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> ErrorGuaranteed {
|
||||
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
|
||||
}
|
||||
|
||||
/// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
|
||||
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_span_note(span, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn struct_span_note(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Note, msg).with_span(span)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_fatal(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
|
||||
self.struct_err(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_warn(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_note(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_bug(msg).emit()
|
||||
}
|
||||
|
||||
/// This excludes lint errors, delayed bugs, and stashed errors.
|
||||
#[inline]
|
||||
pub fn err_count(&self) -> usize {
|
||||
self.inner.borrow().err_count
|
||||
self.inner.borrow().err_guars.len()
|
||||
}
|
||||
|
||||
/// This excludes normal errors, lint errors and delayed bugs. Unless
|
||||
@ -946,36 +737,19 @@ impl DiagCtxt {
|
||||
|
||||
/// This excludes lint errors, delayed bugs, and stashed errors.
|
||||
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.inner.borrow().has_errors().then(|| {
|
||||
// FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
|
||||
#[allow(deprecated)]
|
||||
ErrorGuaranteed::unchecked_error_guaranteed()
|
||||
})
|
||||
self.inner.borrow().has_errors()
|
||||
}
|
||||
|
||||
/// This excludes delayed bugs and stashed errors. Unless absolutely
|
||||
/// necessary, prefer `has_errors` to this method.
|
||||
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
let inner = self.inner.borrow();
|
||||
let result = inner.has_errors() || inner.lint_err_count > 0;
|
||||
result.then(|| {
|
||||
// FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
|
||||
#[allow(deprecated)]
|
||||
ErrorGuaranteed::unchecked_error_guaranteed()
|
||||
})
|
||||
self.inner.borrow().has_errors_or_lint_errors()
|
||||
}
|
||||
|
||||
/// This excludes stashed errors. Unless absolutely necessary, prefer
|
||||
/// `has_errors` or `has_errors_or_lint_errors` to this method.
|
||||
pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||
let inner = self.inner.borrow();
|
||||
let result =
|
||||
inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty();
|
||||
result.then(|| {
|
||||
// FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
|
||||
#[allow(deprecated)]
|
||||
ErrorGuaranteed::unchecked_error_guaranteed()
|
||||
})
|
||||
self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs()
|
||||
}
|
||||
|
||||
pub fn print_error_count(&self, registry: &Registry) {
|
||||
@ -1008,10 +782,10 @@ impl DiagCtxt {
|
||||
.emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings)));
|
||||
}
|
||||
(_, 0) => {
|
||||
inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
|
||||
inner.emit_diagnostic(Diagnostic::new(Error, errors));
|
||||
}
|
||||
(_, _) => {
|
||||
inner.emit_diagnostic(Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
|
||||
inner.emit_diagnostic(Diagnostic::new(Error, format!("{errors}; {warnings}")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1055,7 +829,7 @@ impl DiagCtxt {
|
||||
pub fn abort_if_errors(&self) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.emit_stashed_diagnostics();
|
||||
if inner.has_errors() {
|
||||
if !inner.err_guars.is_empty() {
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
@ -1077,84 +851,6 @@ impl DiagCtxt {
|
||||
self.inner.borrow_mut().emit_diagnostic(diagnostic)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
|
||||
self.create_err(err).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
|
||||
err.into_diagnostic(self, Error)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_warn<'a>(
|
||||
&'a self,
|
||||
warning: impl IntoDiagnostic<'a, ()>,
|
||||
) -> DiagnosticBuilder<'a, ()> {
|
||||
warning.into_diagnostic(self, Warning)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
|
||||
self.create_warn(warning).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_almost_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl IntoDiagnostic<'a, FatalError>,
|
||||
) -> DiagnosticBuilder<'a, FatalError> {
|
||||
fatal.into_diagnostic(self, Fatal)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_almost_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl IntoDiagnostic<'a, FatalError>,
|
||||
) -> FatalError {
|
||||
self.create_almost_fatal(fatal).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl IntoDiagnostic<'a, FatalAbort>,
|
||||
) -> DiagnosticBuilder<'a, FatalAbort> {
|
||||
fatal.into_diagnostic(self, Fatal)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
|
||||
self.create_fatal(fatal).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_bug<'a>(
|
||||
&'a self,
|
||||
bug: impl IntoDiagnostic<'a, BugAbort>,
|
||||
) -> DiagnosticBuilder<'a, BugAbort> {
|
||||
bug.into_diagnostic(self, Bug)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::BugAbort>) -> ! {
|
||||
self.create_bug(bug).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
|
||||
self.create_note(note).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_note<'a>(
|
||||
&'a self,
|
||||
note: impl IntoDiagnostic<'a, ()>,
|
||||
) -> DiagnosticBuilder<'a, ()> {
|
||||
note.into_diagnostic(self, Note)
|
||||
}
|
||||
|
||||
pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
|
||||
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
|
||||
}
|
||||
@ -1175,8 +871,21 @@ impl DiagCtxt {
|
||||
) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
|
||||
// This "error" is an odd duck.
|
||||
// - It's only produce with JSON output.
|
||||
// - It's not emitted the usual way, via `emit_diagnostic`.
|
||||
// - The `$message_type` field is "unused_externs" rather than the usual
|
||||
// "diagnosic".
|
||||
//
|
||||
// We count it as a lint error because it has a lint level. The value
|
||||
// of `loud` (which comes from "unused-externs" or
|
||||
// "unused-externs-silent"), also affects whether it's treated like a
|
||||
// hard error or not.
|
||||
if loud && lint_level.is_error() {
|
||||
inner.lint_err_count += 1;
|
||||
// This `unchecked_error_guaranteed` is valid. It is where the
|
||||
// `ErrorGuaranteed` for unused_extern errors originates.
|
||||
#[allow(deprecated)]
|
||||
inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
|
||||
inner.panic_if_treat_err_as_bug();
|
||||
}
|
||||
|
||||
@ -1229,6 +938,288 @@ impl DiagCtxt {
|
||||
}
|
||||
}
|
||||
|
||||
// This `impl` block contains only the public diagnostic creation/emission API.
|
||||
//
|
||||
// Functions beginning with `struct_`/`create_` create a diagnostic. Other
|
||||
// functions create and emit a diagnostic all in one go.
|
||||
impl DiagCtxt {
|
||||
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
|
||||
#[track_caller]
|
||||
pub fn struct_bug(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, BugAbort> {
|
||||
DiagnosticBuilder::new(self, Bug, msg)
|
||||
}
|
||||
|
||||
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
|
||||
#[track_caller]
|
||||
pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_bug(msg).emit()
|
||||
}
|
||||
|
||||
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
|
||||
#[track_caller]
|
||||
pub fn struct_span_bug(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, BugAbort> {
|
||||
self.struct_bug(msg).with_span(span)
|
||||
}
|
||||
|
||||
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
|
||||
#[track_caller]
|
||||
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_span_bug(span, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_bug<'a>(
|
||||
&'a self,
|
||||
bug: impl IntoDiagnostic<'a, BugAbort>,
|
||||
) -> DiagnosticBuilder<'a, BugAbort> {
|
||||
bug.into_diagnostic(self, Bug)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! {
|
||||
self.create_bug(bug).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_fatal(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, FatalAbort> {
|
||||
DiagnosticBuilder::new(self, Fatal, msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_fatal(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_fatal(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, FatalAbort> {
|
||||
self.struct_fatal(msg).with_span(span)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
self.struct_span_fatal(span, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl IntoDiagnostic<'a, FatalAbort>,
|
||||
) -> DiagnosticBuilder<'a, FatalAbort> {
|
||||
fatal.into_diagnostic(self, Fatal)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
|
||||
self.create_fatal(fatal).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_almost_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl IntoDiagnostic<'a, FatalError>,
|
||||
) -> DiagnosticBuilder<'a, FatalError> {
|
||||
fatal.into_diagnostic(self, Fatal)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_almost_fatal<'a>(
|
||||
&'a self,
|
||||
fatal: impl IntoDiagnostic<'a, FatalError>,
|
||||
) -> FatalError {
|
||||
self.create_almost_fatal(fatal).emit()
|
||||
}
|
||||
|
||||
// FIXME: This method should be removed (every error should have an associated error code).
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
|
||||
DiagnosticBuilder::new(self, Error, msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
|
||||
self.struct_err(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_err(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_> {
|
||||
self.struct_err(msg).with_span(span)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_err(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.struct_span_err(span, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
|
||||
err.into_diagnostic(self, Error)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
|
||||
self.create_err(err).emit()
|
||||
}
|
||||
|
||||
/// Ensures that an error is printed. See `Level::DelayedBug`.
|
||||
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
|
||||
#[track_caller]
|
||||
pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
|
||||
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
|
||||
}
|
||||
|
||||
/// Ensures that an error is printed. See `Level::DelayedBug`.
|
||||
///
|
||||
/// Note: this function used to be called `delay_span_bug`. It was renamed
|
||||
/// to match similar functions like `span_err`, `span_warn`, etc.
|
||||
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
|
||||
#[track_caller]
|
||||
pub fn span_delayed_bug(
|
||||
&self,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> ErrorGuaranteed {
|
||||
DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
|
||||
}
|
||||
|
||||
/// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
|
||||
// No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
|
||||
#[track_caller]
|
||||
pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Warning, msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_warn(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_warn(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
self.struct_warn(msg).with_span(span)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_span_warn(span, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_warn<'a>(
|
||||
&'a self,
|
||||
warning: impl IntoDiagnostic<'a, ()>,
|
||||
) -> DiagnosticBuilder<'a, ()> {
|
||||
warning.into_diagnostic(self, Warning)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
|
||||
self.create_warn(warning).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_note(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Note, msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_note(msg).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_span_note(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Note, msg).with_span(span)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.struct_span_note(span, msg).emit()
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn create_note<'a>(
|
||||
&'a self,
|
||||
note: impl IntoDiagnostic<'a, ()>,
|
||||
) -> DiagnosticBuilder<'a, ()> {
|
||||
note.into_diagnostic(self, Note)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
|
||||
self.create_note(note).emit()
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Help, msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Allow, msg)
|
||||
}
|
||||
|
||||
#[rustc_lint_diagnostics]
|
||||
#[track_caller]
|
||||
pub fn struct_expect(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Expect(id), msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Note: we prefer implementing operations on `DiagCtxt`, rather than
|
||||
// `DiagCtxtInner`, whenever possible. This minimizes functions where
|
||||
// `DiagCtxt::foo()` just borrows `inner` and forwards a call to
|
||||
@ -1236,7 +1227,7 @@ impl DiagCtxt {
|
||||
impl DiagCtxtInner {
|
||||
/// Emit all stashed diagnostics.
|
||||
fn emit_stashed_diagnostics(&mut self) {
|
||||
let has_errors = self.has_errors();
|
||||
let has_errors = !self.err_guars.is_empty();
|
||||
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
|
||||
// Decrement the count tracking the stash; emitting will increment it.
|
||||
if diag.is_error() {
|
||||
@ -1298,9 +1289,13 @@ impl DiagCtxtInner {
|
||||
// when an error is first emitted, also), but maybe there's a case
|
||||
// in which that's not sound? otherwise this is really inefficient.
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
|
||||
// This `unchecked_error_guaranteed` is valid. It is where the
|
||||
// `ErrorGuaranteed` for delayed bugs originates.
|
||||
#[allow(deprecated)]
|
||||
return Some(ErrorGuaranteed::unchecked_error_guaranteed());
|
||||
let guar = ErrorGuaranteed::unchecked_error_guaranteed();
|
||||
self.delayed_bugs
|
||||
.push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
|
||||
return Some(guar);
|
||||
}
|
||||
GoodPathDelayedBug => {
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
@ -1334,7 +1329,6 @@ impl DiagCtxtInner {
|
||||
!self.emitted_diagnostics.insert(diagnostic_hash)
|
||||
};
|
||||
|
||||
let level = diagnostic.level;
|
||||
let is_error = diagnostic.is_error();
|
||||
let is_lint = diagnostic.is_lint.is_some();
|
||||
|
||||
@ -1373,36 +1367,47 @@ impl DiagCtxtInner {
|
||||
}
|
||||
|
||||
if is_error {
|
||||
// This `unchecked_error_guaranteed` is valid. It is where the
|
||||
// `ErrorGuaranteed` for errors and lint errors originates.
|
||||
#[allow(deprecated)]
|
||||
let guar = ErrorGuaranteed::unchecked_error_guaranteed();
|
||||
guaranteed = Some(guar);
|
||||
if is_lint {
|
||||
self.lint_err_count += 1;
|
||||
self.lint_err_guars.push(guar);
|
||||
} else {
|
||||
self.err_count += 1;
|
||||
self.err_guars.push(guar);
|
||||
}
|
||||
self.panic_if_treat_err_as_bug();
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
if level == Level::Error {
|
||||
guaranteed = Some(ErrorGuaranteed::unchecked_error_guaranteed());
|
||||
}
|
||||
});
|
||||
|
||||
guaranteed
|
||||
}
|
||||
|
||||
fn treat_err_as_bug(&self) -> bool {
|
||||
self.flags.treat_err_as_bug.is_some_and(|c| self.err_count + self.lint_err_count >= c.get())
|
||||
self.flags
|
||||
.treat_err_as_bug
|
||||
.is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
|
||||
}
|
||||
|
||||
// Use this one before incrementing `err_count`.
|
||||
fn treat_next_err_as_bug(&self) -> bool {
|
||||
self.flags
|
||||
.treat_err_as_bug
|
||||
.is_some_and(|c| self.err_count + self.lint_err_count + 1 >= c.get())
|
||||
.is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
|
||||
}
|
||||
|
||||
fn has_errors(&self) -> bool {
|
||||
self.err_count > 0
|
||||
fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.err_guars.get(0).copied()
|
||||
}
|
||||
|
||||
fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.has_errors().or_else(|| self.lint_err_guars.get(0).copied())
|
||||
}
|
||||
|
||||
fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
|
||||
self.has_errors_or_lint_errors()
|
||||
.or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
|
||||
}
|
||||
|
||||
fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
|
||||
@ -1412,7 +1417,7 @@ impl DiagCtxtInner {
|
||||
fn flush_delayed(&mut self, kind: DelayedBugKind) {
|
||||
let (bugs, note1) = match kind {
|
||||
DelayedBugKind::Normal => (
|
||||
std::mem::take(&mut self.delayed_bugs),
|
||||
std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(),
|
||||
"no errors encountered even though delayed bugs were created",
|
||||
),
|
||||
DelayedBugKind::GoodPath => (
|
||||
@ -1434,7 +1439,7 @@ impl DiagCtxtInner {
|
||||
{
|
||||
let _ = write!(
|
||||
&mut out,
|
||||
"delayed span bug: {}\n{}\n",
|
||||
"delayed bug: {}\n{}\n",
|
||||
bug.inner
|
||||
.messages
|
||||
.iter()
|
||||
@ -1477,7 +1482,7 @@ impl DiagCtxtInner {
|
||||
fn panic_if_treat_err_as_bug(&self) {
|
||||
if self.treat_err_as_bug() {
|
||||
let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
|
||||
assert_eq!(n, self.err_count + self.lint_err_count);
|
||||
assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
|
||||
if n == 1 {
|
||||
panic!("aborting due to `-Z treat-err-as-bug=1`");
|
||||
} else {
|
||||
@ -1584,6 +1589,7 @@ pub enum Level {
|
||||
ForceWarning(Option<LintExpectationId>),
|
||||
|
||||
/// A warning about the code being compiled. Does not prevent compilation from finishing.
|
||||
/// Will be skipped if `can_emit_warnings` is false.
|
||||
Warning,
|
||||
|
||||
/// A message giving additional context.
|
||||
|
@ -806,7 +806,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(
|
||||
TEST, rustc_error, Normal,
|
||||
template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
||||
template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
||||
),
|
||||
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
|
||||
|
@ -91,10 +91,6 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
|
||||
return None;
|
||||
};
|
||||
|
||||
if new_ty.references_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.state.steps.push((self.state.cur_ty, kind));
|
||||
debug!(
|
||||
"autoderef stage #{:?} is {:?} from {:?}",
|
||||
@ -137,6 +133,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
||||
debug!("overloaded_deref_ty({:?})", ty);
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
if ty.references_error() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// <ty as Deref>
|
||||
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
|
||||
let cause = traits::ObligationCause::misc(self.span, self.body_id);
|
||||
|
@ -16,7 +16,6 @@ use rustc_index::Idx;
|
||||
use rustc_middle::middle::region::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::source_map;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut};
|
||||
|
||||
@ -72,11 +71,7 @@ struct RegionResolutionVisitor<'tcx> {
|
||||
}
|
||||
|
||||
/// Records the lifetime of a local variable as `cx.var_parent`
|
||||
fn record_var_lifetime(
|
||||
visitor: &mut RegionResolutionVisitor<'_>,
|
||||
var_id: hir::ItemLocalId,
|
||||
_sp: Span,
|
||||
) {
|
||||
fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::ItemLocalId) {
|
||||
match visitor.cx.var_parent {
|
||||
None => {
|
||||
// this can happen in extern fn declarations like
|
||||
@ -210,7 +205,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir
|
||||
|
||||
// If this is a binding then record the lifetime of that binding.
|
||||
if let PatKind::Binding(..) = pat.kind {
|
||||
record_var_lifetime(visitor, pat.hir_id.local_id, pat.span);
|
||||
record_var_lifetime(visitor, pat.hir_id.local_id);
|
||||
}
|
||||
|
||||
debug!("resolve_pat - pre-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
|
||||
|
@ -118,9 +118,9 @@ where
|
||||
return Err(err);
|
||||
} else {
|
||||
// HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs
|
||||
// causes an error (span_delayed_bug) during normalization, without reporting an error,
|
||||
// so we need to act as if no error happened, in order to let our callers continue and
|
||||
// report an error later in check_impl_items_against_trait.
|
||||
// causes an delayed bug during normalization, without reporting an error, so we need
|
||||
// to act as if no error happened, in order to let our callers continue and report an
|
||||
// error later in check_impl_items_against_trait.
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@ -1635,6 +1635,12 @@ fn check_method_receiver<'tcx>(
|
||||
let receiver_ty = sig.inputs()[0];
|
||||
let receiver_ty = wfcx.normalize(span, None, receiver_ty);
|
||||
|
||||
// If the receiver already has errors reported, consider it valid to avoid
|
||||
// unnecessary errors (#58712).
|
||||
if receiver_ty.references_error() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if tcx.features().arbitrary_self_types {
|
||||
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
|
||||
// Report error; `arbitrary_self_types` was enabled.
|
||||
@ -1749,9 +1755,7 @@ fn receiver_is_valid<'tcx>(
|
||||
}
|
||||
} else {
|
||||
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
|
||||
// If the receiver already has errors reported due to it, consider it valid to avoid
|
||||
// unnecessary errors (#58712).
|
||||
return receiver_ty.references_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,9 +425,7 @@ fn check_predicates<'tcx>(
|
||||
|
||||
let mut res = Ok(());
|
||||
for (clause, span) in impl1_predicates {
|
||||
if !impl2_predicates
|
||||
.iter()
|
||||
.any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
|
||||
if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(clause.as_predicate(), *pred2))
|
||||
{
|
||||
res = res.and(check_specialization_on(tcx, clause, span))
|
||||
}
|
||||
@ -459,10 +457,8 @@ fn check_predicates<'tcx>(
|
||||
///
|
||||
/// So we make that check in this function and try to raise a helpful error message.
|
||||
fn trait_predicates_eq<'tcx>(
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
predicate1: ty::Predicate<'tcx>,
|
||||
predicate2: ty::Predicate<'tcx>,
|
||||
_span: Span,
|
||||
) -> bool {
|
||||
// FIXME(effects)
|
||||
predicate1 == predicate2
|
||||
|
@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
|
||||
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
|
||||
ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected, expr),
|
||||
ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected),
|
||||
ExprKind::Repeat(element, ref count) => {
|
||||
self.check_expr_repeat(element, count, expected, expr)
|
||||
}
|
||||
@ -1487,7 +1487,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
&self,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
expected: Expectation<'tcx>,
|
||||
_expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
let body = self.tcx.hir().body(block.body);
|
||||
|
||||
|
@ -142,7 +142,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat));
|
||||
debug!("consume_body: param_ty = {:?}", param_ty);
|
||||
|
||||
let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty);
|
||||
let param_place = self.mc.cat_rvalue(param.hir_id, param_ty);
|
||||
|
||||
self.walk_irrefutable_pat(¶m_place, param.pat);
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
deref.region,
|
||||
ty::TypeAndMut { ty: target, mutbl: deref.mutbl },
|
||||
);
|
||||
self.cat_rvalue(expr.hir_id, expr.span, ref_ty)
|
||||
self.cat_rvalue(expr.hir_id, ref_ty)
|
||||
} else {
|
||||
previous()?
|
||||
};
|
||||
@ -285,7 +285,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
| adjustment::Adjust::Borrow(_)
|
||||
| adjustment::Adjust::DynStar => {
|
||||
// Result is an rvalue.
|
||||
Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
|
||||
Ok(self.cat_rvalue(expr.hir_id, target))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,7 +374,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
| hir::ExprKind::Repeat(..)
|
||||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::OffsetOf(..)
|
||||
| hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
|
||||
| hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
| DefKind::AssocFn,
|
||||
_,
|
||||
)
|
||||
| Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)),
|
||||
| Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
|
||||
|
||||
Res::Def(DefKind::Static(_), _) => {
|
||||
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
|
||||
@ -433,13 +433,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(crate) fn cat_rvalue(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
// FIXME: remove
|
||||
_span: Span,
|
||||
expr_ty: Ty<'tcx>,
|
||||
) -> PlaceWithHirId<'tcx> {
|
||||
pub(crate) fn cat_rvalue(&self, hir_id: hir::HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
|
||||
PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
|
||||
}
|
||||
|
||||
@ -487,7 +481,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
};
|
||||
let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl });
|
||||
|
||||
let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty);
|
||||
let base = self.cat_rvalue(expr.hir_id, ref_ty);
|
||||
self.cat_deref(expr, base)
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
|
||||
//
|
||||
// rust-lang/rust#57464: `impl Trait` can leak local
|
||||
// scopes (in manner violating typeck). Therefore, use
|
||||
// `span_delayed_bug` to allow type error over an ICE.
|
||||
// `delayed_bug` to allow type error over an ICE.
|
||||
canonicalizer
|
||||
.tcx
|
||||
.dcx()
|
||||
|
@ -194,16 +194,16 @@ impl<'tcx> Queries<'tcx> {
|
||||
let Some((def_id, _)) = tcx.entry_fn(()) else { return };
|
||||
for attr in tcx.get_attrs(def_id, sym::rustc_error) {
|
||||
match attr.meta_item_list() {
|
||||
// Check if there is a `#[rustc_error(span_delayed_bug_from_inside_query)]`.
|
||||
// Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`.
|
||||
Some(list)
|
||||
if list.iter().any(|list_item| {
|
||||
matches!(
|
||||
list_item.ident().map(|i| i.name),
|
||||
Some(sym::span_delayed_bug_from_inside_query)
|
||||
Some(sym::delayed_bug_from_inside_query)
|
||||
)
|
||||
}) =>
|
||||
{
|
||||
tcx.ensure().trigger_span_delayed_bug(def_id);
|
||||
tcx.ensure().trigger_delayed_bug(def_id);
|
||||
}
|
||||
|
||||
// Bare `#[rustc_error]`.
|
||||
|
@ -108,9 +108,9 @@ pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue
|
||||
// Queries marked with `fatal_cycle` do not need the latter implementation,
|
||||
// as they will raise an fatal error on query cycles instead.
|
||||
rustc_queries! {
|
||||
/// This exists purely for testing the interactions between span_delayed_bug and incremental.
|
||||
query trigger_span_delayed_bug(key: DefId) {
|
||||
desc { "triggering a span delayed bug for testing incremental" }
|
||||
/// This exists purely for testing the interactions between delayed bugs and incremental.
|
||||
query trigger_delayed_bug(key: DefId) {
|
||||
desc { "triggering a delayed bug for testing incremental" }
|
||||
}
|
||||
|
||||
/// Collects the list of all tools registered using `#![register_tool]`.
|
||||
|
@ -82,8 +82,8 @@ impl<'tcx> Region<'tcx> {
|
||||
tcx.intern_region(ty::ReError(reported))
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it
|
||||
/// gets used.
|
||||
/// Constructs a `RegionKind::ReError` region and registers a delayed bug to ensure it gets
|
||||
/// used.
|
||||
#[track_caller]
|
||||
pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> {
|
||||
Region::new_error_with_message(
|
||||
@ -93,8 +93,8 @@ impl<'tcx> Region<'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given
|
||||
/// `msg` to ensure it gets used.
|
||||
/// Constructs a `RegionKind::ReError` region and registers a delayed bug with the given `msg`
|
||||
/// to ensure it gets used.
|
||||
#[track_caller]
|
||||
pub fn new_error_with_message<S: Into<MultiSpan>>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -55,7 +55,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
||||
}
|
||||
fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
|
||||
if self.references_error() {
|
||||
// We must include lint errors and span delayed bugs here.
|
||||
// We must include lint errors and delayed bugs here.
|
||||
if let Some(reported) =
|
||||
ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs())
|
||||
{
|
||||
|
@ -38,16 +38,16 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
|
||||
})
|
||||
}
|
||||
|
||||
/// A query to trigger a `span_delayed_bug`. Clearly, if one has a `tcx` one can already trigger a
|
||||
/// `span_delayed_bug`, so what is the point of this? It exists to help us test `span_delayed_bug`'s
|
||||
/// interactions with the query system and incremental.
|
||||
pub fn trigger_span_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
|
||||
/// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a
|
||||
/// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed
|
||||
/// bugs with the query system and incremental.
|
||||
pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
tcx.def_span(key),
|
||||
"delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]",
|
||||
"delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]",
|
||||
);
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut crate::query::Providers) {
|
||||
*providers = crate::query::Providers { trigger_span_delayed_bug, ..*providers };
|
||||
*providers = crate::query::Providers { trigger_delayed_bug, ..*providers };
|
||||
}
|
||||
|
@ -726,7 +726,7 @@ fn replace_resume_ty_local<'tcx>(
|
||||
/// The async lowering step and the type / lifetime inference / checking are
|
||||
/// still using the `resume` argument for the time being. After this transform,
|
||||
/// the coroutine body doesn't have the `resume` argument.
|
||||
fn transform_gen_context<'tcx>(_tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
fn transform_gen_context<'tcx>(body: &mut Body<'tcx>) {
|
||||
// This leaves the local representing the `resume` argument in place,
|
||||
// but turns it into a regular local variable. This is cheaper than
|
||||
// adjusting all local references in the body after removing it.
|
||||
@ -1733,7 +1733,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
||||
|
||||
// Remove the context argument within generator bodies.
|
||||
if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) {
|
||||
transform_gen_context(tcx, body);
|
||||
transform_gen_context(body);
|
||||
}
|
||||
|
||||
// The original arguments to the function are no longer arguments, mark them as such.
|
||||
|
@ -2,6 +2,7 @@
|
||||
use crate::deref_separator::deref_finder;
|
||||
use rustc_attr::InlineAttr;
|
||||
use rustc_const_eval::transform::validate::validate_types;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::Idx;
|
||||
@ -384,6 +385,17 @@ impl<'tcx> Inliner<'tcx> {
|
||||
}
|
||||
|
||||
let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args);
|
||||
|
||||
// Additionally, check that the body that we're inlining actually agrees
|
||||
// with the ABI of the trait that the item comes from.
|
||||
if let InstanceDef::Item(instance_def_id) = callee.def
|
||||
&& self.tcx.def_kind(instance_def_id) == DefKind::AssocFn
|
||||
&& let instance_fn_sig = self.tcx.fn_sig(instance_def_id).skip_binder()
|
||||
&& instance_fn_sig.abi() != fn_sig.abi()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
|
||||
|
||||
return Some(CallSite { callee, fn_sig, block: bb, source_info });
|
||||
|
@ -29,17 +29,14 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
|
||||
ctx.simplify_bool_cmp(&statement.source_info, rvalue);
|
||||
ctx.simplify_ref_deref(&statement.source_info, rvalue);
|
||||
ctx.simplify_len(&statement.source_info, rvalue);
|
||||
ctx.simplify_cast(&statement.source_info, rvalue);
|
||||
ctx.simplify_cast(rvalue);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.simplify_primitive_clone(block.terminator.as_mut().unwrap(), &mut block.statements);
|
||||
ctx.simplify_intrinsic_assert(
|
||||
block.terminator.as_mut().unwrap(),
|
||||
&mut block.statements,
|
||||
);
|
||||
ctx.simplify_intrinsic_assert(block.terminator.as_mut().unwrap());
|
||||
ctx.simplify_nounwind_call(block.terminator.as_mut().unwrap());
|
||||
simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
|
||||
}
|
||||
@ -143,7 +140,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
|
||||
fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) {
|
||||
if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
|
||||
let operand_ty = operand.ty(self.local_decls, self.tcx);
|
||||
if operand_ty == *cast_ty {
|
||||
@ -277,11 +274,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn simplify_intrinsic_assert(
|
||||
&self,
|
||||
terminator: &mut Terminator<'tcx>,
|
||||
_statements: &mut Vec<Statement<'tcx>>,
|
||||
) {
|
||||
fn simplify_intrinsic_assert(&self, terminator: &mut Terminator<'tcx>) {
|
||||
let TerminatorKind::Call { func, target, .. } = &mut terminator.kind else {
|
||||
return;
|
||||
};
|
||||
|
@ -197,7 +197,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
| sym::unstable
|
||||
| sym::stable
|
||||
| sym::rustc_allowed_through_unstable_modules
|
||||
| sym::rustc_promotable => self.check_stability_promotable(attr, span, target),
|
||||
| sym::rustc_promotable => self.check_stability_promotable(attr, target),
|
||||
sym::link_ordinal => self.check_link_ordinal(attr, span, target),
|
||||
sym::rustc_confusables => self.check_confusables(attr, target),
|
||||
sym::rustc_safe_intrinsic => {
|
||||
@ -2099,7 +2099,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
|
||||
fn check_stability_promotable(&self, attr: &Attribute, target: Target) -> bool {
|
||||
match target {
|
||||
Target::Expression => {
|
||||
self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span });
|
||||
|
@ -656,6 +656,7 @@ symbols! {
|
||||
default_method_body_is_const,
|
||||
default_type_parameter_fallback,
|
||||
default_type_params,
|
||||
delayed_bug_from_inside_query,
|
||||
deny,
|
||||
deprecated,
|
||||
deprecated_safe,
|
||||
@ -1580,7 +1581,6 @@ symbols! {
|
||||
slice_patterns,
|
||||
slicing_syntax,
|
||||
soft,
|
||||
span_delayed_bug_from_inside_query,
|
||||
specialization,
|
||||
speed,
|
||||
spotlight,
|
||||
|
@ -261,12 +261,7 @@ fn encode_predicates<'tcx>(
|
||||
}
|
||||
|
||||
/// Encodes a region using the Itanium C++ ABI as a vendor extended type.
|
||||
fn encode_region<'tcx>(
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
region: Region<'tcx>,
|
||||
dict: &mut FxHashMap<DictKey<'tcx>, usize>,
|
||||
_options: EncodeTyOptions,
|
||||
) -> String {
|
||||
fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>) -> String {
|
||||
// u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
|
||||
let mut s = String::new();
|
||||
match region.kind() {
|
||||
@ -314,7 +309,7 @@ fn encode_args<'tcx>(
|
||||
for arg in args {
|
||||
match arg.unpack() {
|
||||
GenericArgKind::Lifetime(region) => {
|
||||
s.push_str(&encode_region(tcx, region, dict, options));
|
||||
s.push_str(&encode_region(region, dict));
|
||||
}
|
||||
GenericArgKind::Type(ty) => {
|
||||
s.push_str(&encode_ty(tcx, ty, dict, options));
|
||||
@ -704,7 +699,7 @@ fn encode_ty<'tcx>(
|
||||
ty::DynStar => "u7dynstarI",
|
||||
});
|
||||
s.push_str(&encode_predicates(tcx, predicates, dict, options));
|
||||
s.push_str(&encode_region(tcx, *region, dict, options));
|
||||
s.push_str(&encode_region(*region, dict));
|
||||
s.push('E');
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
@ -736,7 +731,6 @@ fn encode_ty<'tcx>(
|
||||
fn transform_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
_options: EncodeTyOptions,
|
||||
) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates
|
||||
.iter()
|
||||
@ -968,7 +962,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
|
||||
ty::Dynamic(predicates, _region, kind) => {
|
||||
ty = Ty::new_dynamic(
|
||||
tcx,
|
||||
transform_predicates(tcx, predicates, options),
|
||||
transform_predicates(tcx, predicates),
|
||||
tcx.lifetimes.re_erased,
|
||||
*kind,
|
||||
);
|
||||
|
@ -15,7 +15,7 @@ use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{fast_reject, TypeFoldable};
|
||||
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub(super) mod structural_traits;
|
||||
@ -612,7 +612,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
||||
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
|
||||
ty::Alias(ty::Inherent | ty::Weak, _) => {
|
||||
unreachable!("Weak and Inherent aliases should have been normalized away already")
|
||||
self.tcx().sess.dcx().span_delayed_bug(
|
||||
DUMMY_SP,
|
||||
format!("could not normalize {self_ty}, it is not WF"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -615,8 +615,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
let UnsatisfiedConst(unsatisfied_const) = self
|
||||
.maybe_add_note_for_unsatisfied_const(
|
||||
&obligation,
|
||||
trait_ref,
|
||||
&trait_predicate,
|
||||
&mut err,
|
||||
span,
|
||||
@ -1480,8 +1478,6 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
|
||||
|
||||
fn maybe_add_note_for_unsatisfied_const(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
err: &mut Diagnostic,
|
||||
span: Span,
|
||||
@ -3359,8 +3355,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
|
||||
fn maybe_add_note_for_unsatisfied_const(
|
||||
&self,
|
||||
_obligation: &PredicateObligation<'tcx>,
|
||||
_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
_trait_predicate: &ty::PolyTraitPredicate<'tcx>,
|
||||
_err: &mut Diagnostic,
|
||||
_span: Span,
|
||||
|
@ -2522,10 +2522,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns a [`Cursor`] pointing to the first gap above the given bound.
|
||||
/// Returns a [`Cursor`] pointing at the gap before the smallest key
|
||||
/// greater than the given bound.
|
||||
///
|
||||
/// Passing [`Bound::Unbounded`] will return a cursor pointing to the start
|
||||
/// of the map.
|
||||
/// Passing `Bound::Included(x)` will return a cursor pointing to the
|
||||
/// gap before the smallest key greater than or equal to `x`.
|
||||
///
|
||||
/// Passing `Bound::Excluded(x)` will return a cursor pointing to the
|
||||
/// gap before the smallest key greater than `x`.
|
||||
///
|
||||
/// Passing `Bound::Unbounded` will return a cursor pointing to the
|
||||
/// gap before the smallest key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2535,17 +2542,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::ops::Bound;
|
||||
///
|
||||
/// let mut a = BTreeMap::new();
|
||||
/// a.insert(1, "a");
|
||||
/// a.insert(2, "b");
|
||||
/// a.insert(3, "c");
|
||||
/// a.insert(4, "d");
|
||||
/// let cursor = a.lower_bound(Bound::Included(&2));
|
||||
/// let map = BTreeMap::from([
|
||||
/// (1, "a"),
|
||||
/// (2, "b"),
|
||||
/// (3, "c"),
|
||||
/// (4, "d"),
|
||||
/// ]);
|
||||
///
|
||||
/// let cursor = map.lower_bound(Bound::Included(&2));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&1, &"a")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&2, &"b")));
|
||||
/// let cursor = a.lower_bound(Bound::Excluded(&2));
|
||||
///
|
||||
/// let cursor = map.lower_bound(Bound::Excluded(&2));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&2, &"b")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&3, &"c")));
|
||||
///
|
||||
/// let cursor = map.lower_bound(Bound::Unbounded);
|
||||
/// assert_eq!(cursor.peek_prev(), None);
|
||||
/// assert_eq!(cursor.peek_next(), Some((&1, &"a")));
|
||||
/// ```
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn lower_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
|
||||
@ -2561,11 +2575,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
Cursor { current: Some(edge), root: self.root.as_ref() }
|
||||
}
|
||||
|
||||
/// Returns a [`CursorMut`] pointing to the first gap above the given bound.
|
||||
/// Returns a [`CursorMut`] pointing at the gap before the smallest key
|
||||
/// greater than the given bound.
|
||||
///
|
||||
/// Passing `Bound::Included(x)` will return a cursor pointing to the
|
||||
/// gap before the smallest key greater than or equal to `x`.
|
||||
///
|
||||
/// Passing [`Bound::Unbounded`] will return a cursor pointing to the start
|
||||
/// of the map.
|
||||
/// Passing `Bound::Excluded(x)` will return a cursor pointing to the
|
||||
/// gap before the smallest key greater than `x`.
|
||||
///
|
||||
/// Passing `Bound::Unbounded` will return a cursor pointing to the
|
||||
/// gap before the smallest key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2575,17 +2595,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::ops::Bound;
|
||||
///
|
||||
/// let mut a = BTreeMap::new();
|
||||
/// a.insert(1, "a");
|
||||
/// a.insert(2, "b");
|
||||
/// a.insert(3, "c");
|
||||
/// a.insert(4, "d");
|
||||
/// let mut cursor = a.lower_bound_mut(Bound::Included(&2));
|
||||
/// let mut map = BTreeMap::from([
|
||||
/// (1, "a"),
|
||||
/// (2, "b"),
|
||||
/// (3, "c"),
|
||||
/// (4, "d"),
|
||||
/// ]);
|
||||
///
|
||||
/// let mut cursor = map.lower_bound_mut(Bound::Included(&2));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&1, &mut "a")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&2, &mut "b")));
|
||||
/// let mut cursor = a.lower_bound_mut(Bound::Excluded(&2));
|
||||
///
|
||||
/// let mut cursor = map.lower_bound_mut(Bound::Excluded(&2));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&3, &mut "c")));
|
||||
///
|
||||
/// let mut cursor = map.lower_bound_mut(Bound::Unbounded);
|
||||
/// assert_eq!(cursor.peek_prev(), None);
|
||||
/// assert_eq!(cursor.peek_next(), Some((&1, &mut "a")));
|
||||
/// ```
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn lower_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
|
||||
@ -2618,10 +2645,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [`Cursor`] pointing at the last gap below the given bound.
|
||||
/// Returns a [`Cursor`] pointing at the gap after the greatest key
|
||||
/// smaller than the given bound.
|
||||
///
|
||||
/// Passing [`Bound::Unbounded`] will return a cursor pointing to the end
|
||||
/// of the map.
|
||||
/// Passing `Bound::Included(x)` will return a cursor pointing to the
|
||||
/// gap after the greatest key smaller than or equal to `x`.
|
||||
///
|
||||
/// Passing `Bound::Excluded(x)` will return a cursor pointing to the
|
||||
/// gap after the greatest key smaller than `x`.
|
||||
///
|
||||
/// Passing `Bound::Unbounded` will return a cursor pointing to the
|
||||
/// gap after the greatest key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2631,17 +2665,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::ops::Bound;
|
||||
///
|
||||
/// let mut a = BTreeMap::new();
|
||||
/// a.insert(1, "a");
|
||||
/// a.insert(2, "b");
|
||||
/// a.insert(3, "c");
|
||||
/// a.insert(4, "d");
|
||||
/// let cursor = a.upper_bound(Bound::Included(&3));
|
||||
/// let map = BTreeMap::from([
|
||||
/// (1, "a"),
|
||||
/// (2, "b"),
|
||||
/// (3, "c"),
|
||||
/// (4, "d"),
|
||||
/// ]);
|
||||
///
|
||||
/// let cursor = map.upper_bound(Bound::Included(&3));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&3, &"c")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&4, &"d")));
|
||||
/// let cursor = a.upper_bound(Bound::Excluded(&3));
|
||||
///
|
||||
/// let cursor = map.upper_bound(Bound::Excluded(&3));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&2, &"b")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&3, &"c")));
|
||||
///
|
||||
/// let cursor = map.upper_bound(Bound::Unbounded);
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&4, &"d")));
|
||||
/// assert_eq!(cursor.peek_next(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn upper_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
|
||||
@ -2657,10 +2698,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
Cursor { current: Some(edge), root: self.root.as_ref() }
|
||||
}
|
||||
|
||||
/// Returns a [`CursorMut`] pointing at the last gap below the given bound.
|
||||
/// Returns a [`CursorMut`] pointing at the gap after the greatest key
|
||||
/// smaller than the given bound.
|
||||
///
|
||||
/// Passing [`Bound::Unbounded`] will return a cursor pointing to the end
|
||||
/// of the map.
|
||||
/// Passing `Bound::Included(x)` will return a cursor pointing to the
|
||||
/// gap after the greatest key smaller than or equal to `x`.
|
||||
///
|
||||
/// Passing `Bound::Excluded(x)` will return a cursor pointing to the
|
||||
/// gap after the greatest key smaller than `x`.
|
||||
///
|
||||
/// Passing `Bound::Unbounded` will return a cursor pointing to the
|
||||
/// gap after the greatest key in the map.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2670,17 +2718,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
/// use std::collections::BTreeMap;
|
||||
/// use std::ops::Bound;
|
||||
///
|
||||
/// let mut a = BTreeMap::new();
|
||||
/// a.insert(1, "a");
|
||||
/// a.insert(2, "b");
|
||||
/// a.insert(3, "c");
|
||||
/// a.insert(4, "d");
|
||||
/// let mut cursor = a.upper_bound_mut(Bound::Included(&3));
|
||||
/// let mut map = BTreeMap::from([
|
||||
/// (1, "a"),
|
||||
/// (2, "b"),
|
||||
/// (3, "c"),
|
||||
/// (4, "d"),
|
||||
/// ]);
|
||||
///
|
||||
/// let mut cursor = map.upper_bound_mut(Bound::Included(&3));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&3, &mut "c")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&4, &mut "d")));
|
||||
/// let mut cursor = a.upper_bound_mut(Bound::Excluded(&3));
|
||||
///
|
||||
/// let mut cursor = map.upper_bound_mut(Bound::Excluded(&3));
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b")));
|
||||
/// assert_eq!(cursor.peek_next(), Some((&3, &mut "c")));
|
||||
///
|
||||
/// let mut cursor = map.upper_bound_mut(Bound::Unbounded);
|
||||
/// assert_eq!(cursor.peek_prev(), Some((&4, &mut "d")));
|
||||
/// assert_eq!(cursor.peek_next(), None);
|
||||
/// ```
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
|
||||
@ -3040,8 +3095,8 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> {
|
||||
|
||||
// Now the tree editing operations
|
||||
impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMutKey` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap before the
|
||||
/// newly inserted element.
|
||||
@ -3083,8 +3138,8 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
|
||||
*self.length += 1;
|
||||
}
|
||||
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMutKey` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap after the
|
||||
/// newly inserted element.
|
||||
@ -3129,19 +3184,16 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
|
||||
*self.length += 1;
|
||||
}
|
||||
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMutKey` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap before the
|
||||
/// newly inserted element.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if:
|
||||
/// - the given key compares less than or equal to the current element (if
|
||||
/// any).
|
||||
/// - the given key compares greater than or equal to the next element (if
|
||||
/// any).
|
||||
/// If the inserted key is not greater than the key before the cursor
|
||||
/// (if any), or if it not less than the key after the cursor (if any),
|
||||
/// then an [`UnorderedKeyError`] is returned since this would
|
||||
/// invalidate the [`Ord`] invariant between the keys of the map.
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
|
||||
if let Some((prev, _)) = self.peek_prev() {
|
||||
@ -3160,19 +3212,16 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMutKey` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap after the
|
||||
/// newly inserted element.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if:
|
||||
/// - the given key compares greater than or equal to the current element
|
||||
/// (if any).
|
||||
/// - the given key compares less than or equal to the previous element (if
|
||||
/// any).
|
||||
/// If the inserted key is not greater than the key before the cursor
|
||||
/// (if any), or if it not less than the key after the cursor (if any),
|
||||
/// then an [`UnorderedKeyError`] is returned since this would
|
||||
/// invalidate the [`Ord`] invariant between the keys of the map.
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
|
||||
if let Some((prev, _)) = self.peek_prev() {
|
||||
@ -3239,10 +3288,10 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMut` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap before the
|
||||
/// After the insertion the cursor will be pointing at the gap after the
|
||||
/// newly inserted element.
|
||||
///
|
||||
/// # Safety
|
||||
@ -3257,8 +3306,8 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
|
||||
unsafe { self.inner.insert_after_unchecked(key, value) }
|
||||
}
|
||||
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMut` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap after the
|
||||
/// newly inserted element.
|
||||
@ -3275,37 +3324,31 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
|
||||
unsafe { self.inner.insert_before_unchecked(key, value) }
|
||||
}
|
||||
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMut` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap before the
|
||||
/// newly inserted element.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if:
|
||||
/// - the given key compares less than or equal to the current element (if
|
||||
/// any).
|
||||
/// - the given key compares greater than or equal to the next element (if
|
||||
/// any).
|
||||
/// If the inserted key is not greater than the key before the cursor
|
||||
/// (if any), or if it not less than the key after the cursor (if any),
|
||||
/// then an [`UnorderedKeyError`] is returned since this would
|
||||
/// invalidate the [`Ord`] invariant between the keys of the map.
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
|
||||
self.inner.insert_after(key, value)
|
||||
}
|
||||
|
||||
/// Inserts a new element into the `BTreeMap` in the gap that the
|
||||
/// `CursorMut` is currently pointing to.
|
||||
/// Inserts a new key-value pair into the map in the gap that the
|
||||
/// cursor is currently pointing to.
|
||||
///
|
||||
/// After the insertion the cursor will be pointing at the gap after the
|
||||
/// newly inserted element.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if:
|
||||
/// - the given key compares greater than or equal to the current element
|
||||
/// (if any).
|
||||
/// - the given key compares less than or equal to the previous element (if
|
||||
/// any).
|
||||
/// If the inserted key is not greater than the key before the cursor
|
||||
/// (if any), or if it not less than the key after the cursor (if any),
|
||||
/// then an [`UnorderedKeyError`] is returned since this would
|
||||
/// invalidate the [`Ord`] invariant between the keys of the map.
|
||||
#[unstable(feature = "btree_cursors", issue = "107540")]
|
||||
pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
|
||||
self.inner.insert_before(key, value)
|
||||
|
@ -1840,7 +1840,9 @@ fn maybe_expand_private_type_alias<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
Some(cx.enter_alias(args, def_id.to_def_id(), |cx| clean_ty(&ty, cx)))
|
||||
Some(cx.enter_alias(args, def_id.to_def_id(), |cx| {
|
||||
cx.with_param_env(def_id.to_def_id(), |cx| clean_ty(&ty, cx))
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
|
||||
|
@ -77,7 +77,7 @@ fn integration_test() {
|
||||
// the repo basically just contains a span_delayed_bug that forces rustc/clippy to panic:
|
||||
/*
|
||||
#![feature(rustc_attrs)]
|
||||
#[rustc_error(span_delayed_bug_from_inside_query)]
|
||||
#[rustc_error(delayed_bug_from_inside_query)]
|
||||
fn main() {}
|
||||
*/
|
||||
|
||||
|
@ -650,7 +650,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(
|
||||
TEST, rustc_error, Normal,
|
||||
template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
||||
template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
|
||||
),
|
||||
rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
|
||||
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
|
||||
|
@ -1,8 +1,8 @@
|
||||
// revisions: cfail1 cfail2
|
||||
// should-ice
|
||||
// error-pattern: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]
|
||||
// error-pattern: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_error(span_delayed_bug_from_inside_query)]
|
||||
#[rustc_error(delayed_bug_from_inside_query)]
|
||||
fn main() {}
|
||||
|
14
tests/rustdoc-ui/normalize-in-inlined-type-alias.rs
Normal file
14
tests/rustdoc-ui/normalize-in-inlined-type-alias.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
// compile-flags: -Znormalize-docs
|
||||
|
||||
trait Woo<T> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Woo<T> for () {
|
||||
type Assoc = ();
|
||||
}
|
||||
|
||||
type Alias<P> = <() as Woo<P>>::Assoc;
|
||||
|
||||
pub fn hello<S>() -> Alias<S> {}
|
@ -1,15 +1,26 @@
|
||||
// Regression test for an ICE: https://github.com/rust-lang/rust/issues/120884
|
||||
// Test that we don't ICE for coercions with type errors.
|
||||
// We still need to properly go through coercions between types with errors instead of
|
||||
// shortcutting and returning success, because we need the adjustments for building the MIR.
|
||||
|
||||
pub fn has_error() -> TypeError {}
|
||||
//~^ ERROR cannot find type `TypeError` in this scope
|
||||
|
||||
pub fn cast() -> *const u8 {
|
||||
// https://github.com/rust-lang/rust/issues/120884
|
||||
// Casting a function item to a data pointer in valid in HIR, but invalid in MIR.
|
||||
// We need an adjustment (ReifyFnPointer) to insert a cast from the function item
|
||||
// to a function pointer as a separate MIR statement.
|
||||
pub fn cast() -> *const u8 {
|
||||
has_error as *const u8
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/120945
|
||||
// This one ICEd, because we skipped the builtin deref from `&TypeError` to `TypeError`.
|
||||
pub fn autoderef_source(e: &TypeError) {
|
||||
//~^ ERROR cannot find type `TypeError` in this scope
|
||||
autoderef_target(e)
|
||||
}
|
||||
|
||||
pub fn autoderef_target(_: &TypeError) {}
|
||||
//~^ ERROR cannot find type `TypeError` in this scope
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,6 +4,18 @@ error[E0412]: cannot find type `TypeError` in this scope
|
||||
LL | pub fn has_error() -> TypeError {}
|
||||
| ^^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0412]: cannot find type `TypeError` in this scope
|
||||
--> $DIR/type-errors.rs:18:29
|
||||
|
|
||||
LL | pub fn autoderef_source(e: &TypeError) {
|
||||
| ^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `TypeError` in this scope
|
||||
--> $DIR/type-errors.rs:23:29
|
||||
|
|
||||
LL | pub fn autoderef_target(_: &TypeError) {}
|
||||
| ^^^^^^^^^ not found in this scope
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0412`.
|
||||
|
@ -4,7 +4,6 @@ const C1: &'static mut [usize] = &mut [];
|
||||
static mut S: usize = 3;
|
||||
const C2: &'static mut usize = unsafe { &mut S };
|
||||
//~^ ERROR: referencing statics in constants
|
||||
//~| ERROR: referencing statics in constants
|
||||
//~| WARN mutable reference of mutable static is discouraged [static_mut_ref]
|
||||
|
||||
fn main() {}
|
||||
|
@ -31,20 +31,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S };
|
||||
= note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
|
||||
= help: to fix this, the value can be extracted to a `const` and then used.
|
||||
|
||||
error[E0658]: referencing statics in constants is unstable
|
||||
--> $DIR/issue-17718-const-bad-values.rs:5:46
|
||||
|
|
||||
LL | const C2: &'static mut usize = unsafe { &mut S };
|
||||
| ^
|
||||
|
|
||||
= note: see issue #119618 <https://github.com/rust-lang/rust/issues/119618> for more information
|
||||
= help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
|
||||
= help: to fix this, the value can be extracted to a `const` and then used.
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 3 previous errors; 1 warning emitted
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0658, E0764.
|
||||
For more information about an error, try `rustc --explain E0658`.
|
||||
|
@ -49,11 +49,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | const READ_MUT: u32 = unsafe { MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static.rs:18:32
|
||||
|
|
||||
LL | const READ_MUT: u32 = unsafe { MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static.rs:24:18
|
||||
|
|
||||
|
@ -49,11 +49,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | const READ_MUT: u32 = unsafe { MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static.rs:18:32
|
||||
|
|
||||
LL | const READ_MUT: u32 = unsafe { MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static.rs:24:18
|
||||
|
|
||||
|
@ -83,21 +83,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:12:15
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:18:15
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO[0] }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:18:15
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO[0] }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:18:15
|
||||
|
|
||||
@ -113,26 +98,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors; 2 warnings emitted
|
||||
|
||||
|
@ -83,21 +83,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:12:15
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:18:15
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO[0] }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:18:15
|
||||
|
|
||||
LL | unsafe { &static_cross_crate::ZERO[0] }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:18:15
|
||||
|
|
||||
@ -113,26 +98,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/const_refers_to_static_cross_crate.rs:28:15
|
||||
|
|
||||
LL | match static_cross_crate::OPT_ZERO {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors; 2 warnings emitted
|
||||
|
||||
|
@ -114,11 +114,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
|
||||
| ^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:32:40
|
||||
|
|
||||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
|
||||
| ^^^
|
||||
help: skipping check that does not even have a feature gate
|
||||
--> $DIR/mutable_references_err.rs:32:35
|
||||
|
|
||||
@ -144,16 +139,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:47:44
|
||||
|
|
||||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:51:45
|
||||
|
|
||||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
|
||||
| ^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:51:45
|
||||
|
|
||||
|
@ -114,11 +114,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
|
||||
| ^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:32:40
|
||||
|
|
||||
LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
|
||||
| ^^^
|
||||
help: skipping check that does not even have a feature gate
|
||||
--> $DIR/mutable_references_err.rs:32:35
|
||||
|
|
||||
@ -144,16 +139,6 @@ help: skipping check for `const_refs_to_static` feature
|
||||
|
|
||||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:47:44
|
||||
|
|
||||
LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
|
||||
| ^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:51:45
|
||||
|
|
||||
LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
|
||||
| ^^^^^^^^^^^
|
||||
help: skipping check for `const_refs_to_static` feature
|
||||
--> $DIR/mutable_references_err.rs:51:45
|
||||
|
|
||||
|
@ -6,7 +6,6 @@ const C1_READ: () = {
|
||||
assert!(*C1 == 0);
|
||||
};
|
||||
const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; //~ERROR: referencing statics in constants is unstable
|
||||
//~^ERROR: referencing statics in constants is unstable
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -22,19 +22,6 @@ LL | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
|
||||
= note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
|
||||
= help: to fix this, the value can be extracted to a `const` and then used.
|
||||
|
||||
error[E0658]: referencing statics in constants is unstable
|
||||
--> $DIR/feature-gate-const-refs-to-static.rs:8:52
|
||||
|
|
||||
LL | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
|
||||
| ^^^^^
|
||||
|
|
||||
= note: see issue #119618 <https://github.com/rust-lang/rust/issues/119618> for more information
|
||||
= help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
|
||||
= help: to fix this, the value can be extracted to a `const` and then used.
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
19
tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
Normal file
19
tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// compile-flags: -Znext-solver
|
||||
|
||||
#![feature(lazy_type_alias)]
|
||||
//~^ WARN the feature `lazy_type_alias` is incomplete
|
||||
|
||||
trait Foo {}
|
||||
|
||||
type A<T: Foo> = T;
|
||||
|
||||
struct W<T>(T);
|
||||
|
||||
// For `W<A<usize>>` to be WF, `A<usize>: Sized` must hold. However, when assembling
|
||||
// alias bounds for `A<usize>`, we try to normalize it, but it doesn't hold because
|
||||
// `usize: Foo` doesn't hold. Therefore we ICE, because we don't expect to still
|
||||
// encounter weak types in `assemble_alias_bound_candidates_recur`.
|
||||
fn hello(_: W<A<usize>>) {}
|
||||
//~^ ERROR the type `W<A<usize>>` is not well-formed
|
||||
|
||||
fn main() {}
|
17
tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
Normal file
17
tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/alias-bounds-when-not-wf.rs:3:12
|
||||
|
|
||||
LL | #![feature(lazy_type_alias)]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: the type `W<A<usize>>` is not well-formed
|
||||
--> $DIR/alias-bounds-when-not-wf.rs:16:13
|
||||
|
|
||||
LL | fn hello(_: W<A<usize>>) {}
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
32
tests/ui/mir/inline-wrong-abi.rs
Normal file
32
tests/ui/mir/inline-wrong-abi.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// compile-flags: -Zpolymorphize=on -Zinline-mir=yes -Zmir-opt-level=0
|
||||
|
||||
#![feature(fn_traits, unboxed_closures)]
|
||||
struct Foo<T>(T);
|
||||
|
||||
impl<T: Copy> Fn<()> for Foo<T> {
|
||||
extern "C" fn call(&self, _: ()) -> T {
|
||||
//~^ ERROR method `call` has an incompatible type for trait
|
||||
match *self {
|
||||
Foo(t) => t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> FnMut<()> for Foo<T> {
|
||||
extern "rust-call" fn call_mut(&mut self, _: ()) -> T {
|
||||
self.call(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> FnOnce<()> for Foo<T> {
|
||||
type Output = T;
|
||||
|
||||
extern "rust-call" fn call_once(self, _: ()) -> T {
|
||||
self.call(())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let t: u8 = 1;
|
||||
println!("{}", Foo(t)());
|
||||
}
|
12
tests/ui/mir/inline-wrong-abi.stderr
Normal file
12
tests/ui/mir/inline-wrong-abi.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0053]: method `call` has an incompatible type for trait
|
||||
--> $DIR/inline-wrong-abi.rs:7:5
|
||||
|
|
||||
LL | extern "C" fn call(&self, _: ()) -> T {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "C" fn
|
||||
|
|
||||
= note: expected signature `extern "rust-call" fn(&Foo<_>, ()) -> _`
|
||||
found signature `extern "C" fn(&Foo<_>, ()) -> _`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0053`.
|
@ -12,7 +12,6 @@ const fn g(x: &mut [u32; 8]) {
|
||||
//~^^ ERROR thread-local statics cannot be accessed
|
||||
//~| ERROR mutable references are not allowed
|
||||
//~| ERROR use of mutable static is unsafe
|
||||
//~| referencing statics
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -37,18 +37,6 @@ error[E0625]: thread-local statics cannot be accessed at compile-time
|
||||
LL | std::mem::swap(x, &mut STATIC_VAR_2)
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0658]: referencing statics in constant functions is unstable
|
||||
--> $DIR/thread-local-static.rs:10:28
|
||||
|
|
||||
LL | std::mem::swap(x, &mut STATIC_VAR_2)
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #119618 <https://github.com/rust-lang/rust/issues/119618> for more information
|
||||
= help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
|
||||
= help: to fix this, the value can be extracted to a `const` and then used.
|
||||
|
||||
error[E0658]: mutable references are not allowed in constant functions
|
||||
--> $DIR/thread-local-static.rs:10:23
|
||||
|
|
||||
@ -59,7 +47,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2)
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 5 previous errors; 1 warning emitted
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
|
||||
Some errors have detailed explanations: E0133, E0625, E0658.
|
||||
For more information about an error, try `rustc --explain E0133`.
|
||||
|
@ -1,12 +1,12 @@
|
||||
// compile-flags: -Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs
|
||||
// failure-status: 101
|
||||
// error-pattern: aborting due to `-Z treat-err-as-bug=1`
|
||||
// error-pattern: [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental
|
||||
// error-pattern: [trigger_delayed_bug] triggering a delayed bug for testing incremental
|
||||
// normalize-stderr-test "note: .*\n\n" -> ""
|
||||
// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
|
||||
// rustc-env:RUST_BACKTRACE=0
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_error(span_delayed_bug_from_inside_query)]
|
||||
#[rustc_error(delayed_bug_from_inside_query)]
|
||||
fn main() {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: internal compiler error: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]
|
||||
error: internal compiler error: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]
|
||||
--> $DIR/span_delayed_bug.rs:12:1
|
||||
|
|
||||
LL | fn main() {}
|
||||
@ -7,5 +7,5 @@ LL | fn main() {}
|
||||
error: the compiler unexpectedly panicked. this is a bug.
|
||||
|
||||
query stack during panic:
|
||||
#0 [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental
|
||||
#0 [trigger_delayed_bug] triggering a delayed bug for testing incremental
|
||||
end of query stack
|
||||
|
31
tests/ui/typeck/issue-116864.rs
Normal file
31
tests/ui/typeck/issue-116864.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// compile-flags: -Znext-solver
|
||||
// check-pass
|
||||
// edition: 2021
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
trait Baz {
|
||||
type Param;
|
||||
}
|
||||
|
||||
trait FnMutFut<P, R>: FnMut(P) -> Self::Future {
|
||||
type Future: Future<Output = R>;
|
||||
}
|
||||
|
||||
impl<P, F, FUT, R> FnMutFut<P, R> for F
|
||||
where
|
||||
F: FnMut(P) -> FUT,
|
||||
FUT: Future<Output = R>,
|
||||
{
|
||||
type Future = FUT;
|
||||
}
|
||||
|
||||
async fn foo<BAZ>(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>)
|
||||
where
|
||||
BAZ: Baz<Param = i32>,
|
||||
{
|
||||
cb(&1i32).await;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
@ -810,7 +810,7 @@ project-stable-mir = [
|
||||
"/library/panic_abort" = ["libs"]
|
||||
"/library/panic_unwind" = ["libs"]
|
||||
"/library/proc_macro" = ["@petrochenkov"]
|
||||
"/library/std" = ["libs"]
|
||||
"/library/std" = ["libs", "@ChrisDenton"]
|
||||
"/library/std/src/sys/pal/windows" = ["@ChrisDenton"]
|
||||
"/library/stdarch" = ["libs"]
|
||||
"/library/test" = ["libs"]
|
||||
|
Loading…
Reference in New Issue
Block a user