1
Fork 0

Auto merge of #106573 - matthiaskrgr:rollup-zkgfsta, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #101936 (Migrating rustc_infer to session diagnostics (part 3))
 - #104081 (PhantomData layout guarantees)
 - #104543 (Migrate `codegen_ssa` to diagnostics structs - [Part 3])
 - #105128 (Add O(1) `Vec -> VecDeque` conversion guarantee)
 - #105517 (Fix process-panic-after-fork.rs to pass on newer versions of Android.)
 - #105859 (Point out span where we could introduce higher-ranked lifetime)
 - #106509 (Detect closures assigned to binding in block)
 - #106553 (docs: make `HashSet::retain` doctest more clear)
 - #106556 (rustdoc: remove no-op mobile CSS `.content { margin-left: 0 }`)
 - #106564 (Change to immutable borrow when cloning element of RepeatN)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-01-07 22:42:39 +00:00
commit e5d46a5bda
44 changed files with 1915 additions and 755 deletions

View file

@ -3890,6 +3890,7 @@ dependencies = [
"rustc_span", "rustc_span",
"rustc_symbol_mangling", "rustc_symbol_mangling",
"rustc_target", "rustc_target",
"rustc_type_ir",
"serde_json", "serde_json",
"smallvec", "smallvec",
"snap", "snap",
@ -4024,6 +4025,7 @@ dependencies = [
"rustc_serialize", "rustc_serialize",
"rustc_span", "rustc_span",
"rustc_target", "rustc_target",
"rustc_type_ir",
"serde", "serde",
"serde_json", "serde_json",
"termcolor", "termcolor",

View file

@ -440,15 +440,14 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
closure_kind: &str, closure_kind: &str,
borrowed_path: &str, borrowed_path: &str,
capture_span: Span, capture_span: Span,
scope: &str,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let mut err = struct_span_err!( let mut err = struct_span_err!(
self, self,
closure_span, closure_span,
E0373, E0373,
"{} may outlive the current function, but it borrows {}, which is owned by the current \ "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
function", which is owned by the current {scope}",
closure_kind,
borrowed_path,
); );
err.span_label(capture_span, format!("{} is borrowed here", borrowed_path)) err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
.span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path)); .span_label(closure_span, format!("may outlive borrowed value {}", borrowed_path));

View file

@ -1423,6 +1423,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// //
// then just use the normal error. The closure isn't escaping // then just use the normal error. The closure isn't escaping
// and `move` will not help here. // and `move` will not help here.
(
Some(name),
BorrowExplanation::UsedLater(LaterUseKind::ClosureCapture, var_or_use_span, _),
) => self.report_escaping_closure_capture(
borrow_spans,
borrow_span,
&RegionName {
name: self.synthesize_region_name(),
source: RegionNameSource::Static,
},
ConstraintCategory::CallArgument(None),
var_or_use_span,
&format!("`{}`", name),
"block",
),
( (
Some(name), Some(name),
BorrowExplanation::MustBeValidFor { BorrowExplanation::MustBeValidFor {
@ -1443,6 +1458,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
category, category,
span, span,
&format!("`{}`", name), &format!("`{}`", name),
"function",
), ),
( (
name, name,
@ -1895,6 +1911,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some(err) Some(err)
} }
#[instrument(level = "debug", skip(self))]
fn report_escaping_closure_capture( fn report_escaping_closure_capture(
&mut self, &mut self,
use_span: UseSpans<'tcx>, use_span: UseSpans<'tcx>,
@ -1903,6 +1920,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
category: ConstraintCategory<'tcx>, category: ConstraintCategory<'tcx>,
constraint_span: Span, constraint_span: Span,
captured_var: &str, captured_var: &str,
scope: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use(); let args_span = use_span.args_or_use();
@ -1933,8 +1951,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None => "closure", None => "closure",
}; };
let mut err = let mut err = self.cannot_capture_in_long_lived_closure(
self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span); args_span,
kind,
captured_var,
var_span,
scope,
);
err.span_suggestion_verbose( err.span_suggestion_verbose(
sugg_span, sugg_span,
&format!( &format!(
@ -1956,10 +1979,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) { if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
err.note( err.note(
"async blocks are not executed immediately and must either take a \ "async blocks are not executed immediately and must either take a \
reference or ownership of outside variables they use", reference or ownership of outside variables they use",
); );
} else { } else {
let msg = format!("function requires argument type to outlive `{}`", fr_name); let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
err.span_note(constraint_span, &msg); err.span_note(constraint_span, &msg);
} }
} }

View file

@ -444,6 +444,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// First span returned points to the location of the conflicting use /// First span returned points to the location of the conflicting use
/// Second span if `Some` is returned in the case of closures and points /// Second span if `Some` is returned in the case of closures and points
/// to the use of the path /// to the use of the path
#[instrument(level = "debug", skip(self))]
fn later_use_kind( fn later_use_kind(
&self, &self,
borrow: &BorrowData<'tcx>, borrow: &BorrowData<'tcx>,
@ -461,11 +462,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let block = &self.body.basic_blocks[location.block]; let block = &self.body.basic_blocks[location.block];
let kind = if let Some(&Statement { let kind = if let Some(&Statement {
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), _)), kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)),
.. ..
}) = block.statements.get(location.statement_index) }) = block.statements.get(location.statement_index)
{ {
LaterUseKind::FakeLetRead if let Some(l) = place.as_local()
&& let local_decl = &self.body.local_decls[l]
&& local_decl.ty.is_closure()
{
LaterUseKind::ClosureCapture
} else {
LaterUseKind::FakeLetRead
}
} else if self.was_captured_by_trait_object(borrow) { } else if self.was_captured_by_trait_object(borrow) {
LaterUseKind::TraitCapture LaterUseKind::TraitCapture
} else if location.statement_index == block.statements.len() { } else if location.statement_index == block.statements.len() {

View file

@ -200,7 +200,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
/// increment the counter. /// increment the counter.
/// ///
/// This is _not_ idempotent. Call `give_region_a_name` when possible. /// This is _not_ idempotent. Call `give_region_a_name` when possible.
fn synthesize_region_name(&self) -> Symbol { pub(crate) fn synthesize_region_name(&self) -> Symbol {
let c = self.next_region_name.replace_with(|counter| *counter + 1); let c = self.next_region_name.replace_with(|counter| *counter + 1);
Symbol::intern(&format!("'{:?}", c)) Symbol::intern(&format!("'{:?}", c))
} }

View file

@ -8,8 +8,8 @@ use crate::va_arg::emit_va_arg;
use crate::value::Value; use crate::value::Value;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh}; use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::traits::*;
@ -284,15 +284,11 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
_ => bug!(), _ => bug!(),
}, },
None => { None => {
span_invalid_monomorphization_error( tcx.sess.emit_err(InvalidMonomorphization::BasicIntegerType {
tcx.sess,
span, span,
&format!( name,
"invalid monomorphization of `{}` intrinsic: \ ty,
expected basic integer type, found `{}`", });
name, ty
),
);
return; return;
} }
} }
@ -838,40 +834,24 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
llret_ty: &'ll Type, llret_ty: &'ll Type,
span: Span, span: Span,
) -> Result<&'ll Value, ()> { ) -> Result<&'ll Value, ()> {
// macros for error handling:
#[allow(unused_macro_rules)]
macro_rules! emit_error {
($msg: tt) => {
emit_error!($msg, )
};
($msg: tt, $($fmt: tt)*) => {
span_invalid_monomorphization_error(
bx.sess(), span,
&format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
name, $($fmt)*));
}
}
macro_rules! return_error { macro_rules! return_error {
($($fmt: tt)*) => { ($diag: expr) => {{
{ bx.sess().emit_err($diag);
emit_error!($($fmt)*); return Err(());
return Err(()); }};
}
}
} }
macro_rules! require { macro_rules! require {
($cond: expr, $($fmt: tt)*) => { ($cond: expr, $diag: expr) => {
if !$cond { if !$cond {
return_error!($($fmt)*); return_error!($diag);
} }
}; };
} }
macro_rules! require_simd { macro_rules! require_simd {
($ty: expr, $position: expr) => { ($ty: expr, $diag: expr) => {
require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty) require!($ty.is_simd(), $diag)
}; };
} }
@ -881,7 +861,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let arg_tys = sig.inputs(); let arg_tys = sig.inputs();
if name == sym::simd_select_bitmask { if name == sym::simd_select_bitmask {
require_simd!(arg_tys[1], "argument"); require_simd!(
arg_tys[1],
InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
);
let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let expected_int_bits = (len.max(8) - 1).next_power_of_two(); let expected_int_bits = (len.max(8) - 1).next_power_of_two();
@ -902,12 +886,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty)); let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
bx.load(int_ty, ptr, Align::ONE) bx.load(int_ty, ptr, Align::ONE)
} }
_ => return_error!( _ => return_error!(InvalidMonomorphization::InvalidBitmask {
"invalid bitmask `{}`, expected `u{}` or `[u8; {}]`", span,
name,
mask_ty, mask_ty,
expected_int_bits, expected_int_bits,
expected_bytes expected_bytes
), }),
}; };
let i1 = bx.type_i1(); let i1 = bx.type_i1();
@ -919,7 +904,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
} }
// every intrinsic below takes a SIMD vector as its first argument // every intrinsic below takes a SIMD vector as its first argument
require_simd!(arg_tys[0], "input"); require_simd!(arg_tys[0], InvalidMonomorphization::SimdInput { span, name, ty: arg_tys[0] });
let in_ty = arg_tys[0]; let in_ty = arg_tys[0];
let comparison = match name { let comparison = match name {
@ -934,23 +919,24 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx()); let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
if let Some(cmp_op) = comparison { if let Some(cmp_op) = comparison {
require_simd!(ret_ty, "return"); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!( require!(
in_len == out_len, in_len == out_len,
"expected return type with length {} (same as input type `{}`), \ InvalidMonomorphization::ReturnLengthInputType {
found `{}` with length {}", span,
in_len, name,
in_ty, in_len,
ret_ty, in_ty,
out_len ret_ty,
out_len
}
); );
require!( require!(
bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
"expected return type with integer elements, found `{}` with non-integer `{}`", InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty }
ret_ty,
out_ty
); );
return Ok(compare_simd_types( return Ok(compare_simd_types(
@ -975,10 +961,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
span_bug!(span, "could not evaluate shuffle index array length") span_bug!(span, "could not evaluate shuffle index array length")
}) })
} }
_ => return_error!( _ => return_error!(InvalidMonomorphization::SimdShuffle {
"simd_shuffle index must be an array of `u32`, got `{}`", span,
args[2].layout.ty name,
), ty: args[2].layout.ty
}),
} }
} else { } else {
stripped.parse().unwrap_or_else(|_| { stripped.parse().unwrap_or_else(|_| {
@ -986,23 +973,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}) })
}; };
require_simd!(ret_ty, "return"); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
require!( require!(
out_len == n, out_len == n,
"expected return type of length {}, found `{}` with length {}", InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
n,
ret_ty,
out_len
); );
require!( require!(
in_elem == out_ty, in_elem == out_ty,
"expected return element type `{}` (element of input `{}`), \ InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
found `{}` with element type `{}`",
in_elem,
in_ty,
ret_ty,
out_ty
); );
let total_len = u128::from(in_len) * 2; let total_len = u128::from(in_len) * 2;
@ -1015,15 +994,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let val = bx.const_get_elt(vector, i as u64); let val = bx.const_get_elt(vector, i as u64);
match bx.const_to_opt_u128(val, true) { match bx.const_to_opt_u128(val, true) {
None => { None => {
emit_error!("shuffle index #{} is not a constant", arg_idx); bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexNotConstant {
span,
name,
arg_idx,
});
None None
} }
Some(idx) if idx >= total_len => { Some(idx) if idx >= total_len => {
emit_error!( bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
"shuffle index #{} is out of bounds (limit {})", span,
name,
arg_idx, arg_idx,
total_len total_len,
); });
None None
} }
Some(idx) => Some(bx.const_i32(idx as i32)), Some(idx) => Some(bx.const_i32(idx as i32)),
@ -1044,10 +1028,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
if name == sym::simd_insert { if name == sym::simd_insert {
require!( require!(
in_elem == arg_tys[2], in_elem == arg_tys[2],
"expected inserted type `{}` (element of input `{}`), found `{}`", InvalidMonomorphization::InsertedType {
in_elem, span,
in_ty, name,
arg_tys[2] in_elem,
in_ty,
out_ty: arg_tys[2]
}
); );
return Ok(bx.insert_element( return Ok(bx.insert_element(
args[0].immediate(), args[0].immediate(),
@ -1058,10 +1045,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
if name == sym::simd_extract { if name == sym::simd_extract {
require!( require!(
ret_ty == in_elem, ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`", InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
in_elem,
in_ty,
ret_ty
); );
return Ok(bx.extract_element(args[0].immediate(), args[1].immediate())); return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()));
} }
@ -1069,17 +1053,18 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
if name == sym::simd_select { if name == sym::simd_select {
let m_elem_ty = in_elem; let m_elem_ty = in_elem;
let m_len = in_len; let m_len = in_len;
require_simd!(arg_tys[1], "argument"); require_simd!(
arg_tys[1],
InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
);
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
require!( require!(
m_len == v_len, m_len == v_len,
"mismatched lengths: mask length `{}` != other vector length `{}`", InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
m_len,
v_len
); );
match m_elem_ty.kind() { match m_elem_ty.kind() {
ty::Int(_) => {} ty::Int(_) => {}
_ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty), _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
} }
// truncate the mask to a vector of i1s // truncate the mask to a vector of i1s
let i1 = bx.type_i1(); let i1 = bx.type_i1();
@ -1111,11 +1096,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
args[0].immediate(), args[0].immediate(),
i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()), i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
), ),
_ => return_error!( _ => return_error!(InvalidMonomorphization::VectorArgument {
"vector argument `{}`'s element type `{}`, expected integer element type", span,
name,
in_ty, in_ty,
in_elem in_elem
), }),
}; };
// Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position. // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
@ -1150,12 +1136,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty)); let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
return Ok(bx.load(array_ty, ptr, Align::ONE)); return Ok(bx.load(array_ty, ptr, Align::ONE));
} }
_ => return_error!( _ => return_error!(InvalidMonomorphization::CannotReturn {
"cannot return `{}`, expected `u{}` or `[u8; {}]`", span,
name,
ret_ty, ret_ty,
expected_int_bits, expected_int_bits,
expected_bytes expected_bytes
), }),
} }
} }
@ -1168,25 +1155,11 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
span: Span, span: Span,
args: &[OperandRef<'tcx, &'ll Value>], args: &[OperandRef<'tcx, &'ll Value>],
) -> Result<&'ll Value, ()> { ) -> Result<&'ll Value, ()> {
#[allow(unused_macro_rules)]
macro_rules! emit_error {
($msg: tt) => {
emit_error!($msg, )
};
($msg: tt, $($fmt: tt)*) => {
span_invalid_monomorphization_error(
bx.sess(), span,
&format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
name, $($fmt)*));
}
}
macro_rules! return_error { macro_rules! return_error {
($($fmt: tt)*) => { ($diag: expr) => {{
{ bx.sess().emit_err($diag);
emit_error!($($fmt)*); return Err(());
return Err(()); }};
}
}
} }
let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() { let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
@ -1194,16 +1167,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
match f.bit_width() { match f.bit_width() {
32 => ("f32", elem_ty), 32 => ("f32", elem_ty),
64 => ("f64", elem_ty), 64 => ("f64", elem_ty),
_ => { _ => return_error!(InvalidMonomorphization::FloatingPointVector {
return_error!( span,
"unsupported element type `{}` of floating-point vector `{}`", name,
f.name_str(), f_ty: *f,
in_ty in_ty,
); }),
}
} }
} else { } else {
return_error!("`{}` is not a floating-point type", in_ty); return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
}; };
let vec_ty = bx.type_vector(elem_ty, in_len); let vec_ty = bx.type_vector(elem_ty, in_len);
@ -1225,7 +1197,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)), sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
_ => return_error!("unrecognized intrinsic `{}`", name), _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
}; };
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str); let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty); let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
@ -1319,37 +1291,48 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
// * M: any integer width is supported, will be truncated to i1 // * M: any integer width is supported, will be truncated to i1
// All types must be simd vector types // All types must be simd vector types
require_simd!(in_ty, "first"); require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
require_simd!(arg_tys[1], "second"); require_simd!(
require_simd!(arg_tys[2], "third"); arg_tys[1],
require_simd!(ret_ty, "return"); InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
);
require_simd!(
arg_tys[2],
InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
);
require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
// Of the same length: // Of the same length:
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
require!( require!(
in_len == out_len, in_len == out_len,
"expected {} argument with length {} (same as input type `{}`), \ InvalidMonomorphization::SecondArgumentLength {
found `{}` with length {}", span,
"second", name,
in_len, in_len,
in_ty, in_ty,
arg_tys[1], arg_ty: arg_tys[1],
out_len out_len
}
); );
require!( require!(
in_len == out_len2, in_len == out_len2,
"expected {} argument with length {} (same as input type `{}`), \ InvalidMonomorphization::ThirdArgumentLength {
found `{}` with length {}", span,
"third", name,
in_len, in_len,
in_ty, in_ty,
arg_tys[2], arg_ty: arg_tys[2],
out_len2 out_len: out_len2
}
); );
// The return type must match the first argument type // The return type must match the first argument type
require!(ret_ty == in_ty, "expected return type `{}`, found `{}`", in_ty, ret_ty); require!(
ret_ty == in_ty,
InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
);
// This counts how many pointers // This counts how many pointers
fn ptr_count(t: Ty<'_>) -> usize { fn ptr_count(t: Ty<'_>) -> usize {
@ -1376,15 +1359,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
_ => { _ => {
require!( require!(
false, false,
"expected element type `{}` of second argument `{}` \ InvalidMonomorphization::ExpectedElementType {
to be a pointer to the element type `{}` of the first \ span,
argument `{}`, found `{}` != `*_ {}`", name,
element_ty1, expected_element: element_ty1,
arg_tys[1], second_arg: arg_tys[1],
in_elem, in_elem,
in_ty, in_ty,
element_ty1, mutability: ExpectedPointerMutability::Not,
in_elem }
); );
unreachable!(); unreachable!();
} }
@ -1400,10 +1383,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
_ => { _ => {
require!( require!(
false, false,
"expected element type `{}` of third argument `{}` \ InvalidMonomorphization::ThirdArgElementType {
to be a signed integer type", span,
element_ty2, name,
arg_tys[2] expected_element: element_ty2,
third_arg: arg_tys[2]
}
); );
} }
} }
@ -1452,32 +1437,40 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
// * M: any integer width is supported, will be truncated to i1 // * M: any integer width is supported, will be truncated to i1
// All types must be simd vector types // All types must be simd vector types
require_simd!(in_ty, "first"); require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
require_simd!(arg_tys[1], "second"); require_simd!(
require_simd!(arg_tys[2], "third"); arg_tys[1],
InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
);
require_simd!(
arg_tys[2],
InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
);
// Of the same length: // Of the same length:
let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx()); let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
require!( require!(
in_len == element_len1, in_len == element_len1,
"expected {} argument with length {} (same as input type `{}`), \ InvalidMonomorphization::SecondArgumentLength {
found `{}` with length {}", span,
"second", name,
in_len, in_len,
in_ty, in_ty,
arg_tys[1], arg_ty: arg_tys[1],
element_len1 out_len: element_len1
}
); );
require!( require!(
in_len == element_len2, in_len == element_len2,
"expected {} argument with length {} (same as input type `{}`), \ InvalidMonomorphization::ThirdArgumentLength {
found `{}` with length {}", span,
"third", name,
in_len, in_len,
in_ty, in_ty,
arg_tys[2], arg_ty: arg_tys[2],
element_len2 out_len: element_len2
}
); );
// This counts how many pointers // This counts how many pointers
@ -1508,15 +1501,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
_ => { _ => {
require!( require!(
false, false,
"expected element type `{}` of second argument `{}` \ InvalidMonomorphization::ExpectedElementType {
to be a pointer to the element type `{}` of the first \ span,
argument `{}`, found `{}` != `*mut {}`", name,
element_ty1, expected_element: element_ty1,
arg_tys[1], second_arg: arg_tys[1],
in_elem, in_elem,
in_ty, in_ty,
element_ty1, mutability: ExpectedPointerMutability::Mut,
in_elem }
); );
unreachable!(); unreachable!();
} }
@ -1531,10 +1524,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
_ => { _ => {
require!( require!(
false, false,
"expected element type `{}` of third argument `{}` \ InvalidMonomorphization::ThirdArgElementType {
be a signed integer type", span,
element_ty2, name,
arg_tys[2] expected_element: element_ty2,
third_arg: arg_tys[2]
}
); );
} }
} }
@ -1581,10 +1576,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
if name == sym::$name { if name == sym::$name {
require!( require!(
ret_ty == in_elem, ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`", InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
in_elem,
in_ty,
ret_ty
); );
return match in_elem.kind() { return match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => { ty::Int(_) | ty::Uint(_) => {
@ -1607,25 +1599,28 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
32 => bx.const_real(bx.type_f32(), $identity), 32 => bx.const_real(bx.type_f32(), $identity),
64 => bx.const_real(bx.type_f64(), $identity), 64 => bx.const_real(bx.type_f64(), $identity),
v => return_error!( v => return_error!(
r#" InvalidMonomorphization::UnsupportedSymbolOfSize {
unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, span,
sym::$name, name,
in_ty, symbol: sym::$name,
in_elem, in_ty,
v, in_elem,
ret_ty size: v,
ret_ty
}
), ),
} }
}; };
Ok(bx.$float_reduce(acc, args[0].immediate())) Ok(bx.$float_reduce(acc, args[0].immediate()))
} }
_ => return_error!( _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
"unsupported {} from `{}` with element `{}` to `{}`", span,
sym::$name, name,
symbol: sym::$name,
in_ty, in_ty,
in_elem, in_elem,
ret_ty ret_ty
), }),
}; };
} }
}; };
@ -1653,22 +1648,20 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
if name == sym::$name { if name == sym::$name {
require!( require!(
ret_ty == in_elem, ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`", InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
in_elem,
in_ty,
ret_ty
); );
return match in_elem.kind() { return match in_elem.kind() {
ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)), ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)),
ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)), ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)),
ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())), ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())),
_ => return_error!( _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
"unsupported {} from `{}` with element `{}` to `{}`", span,
sym::$name, name,
symbol: sym::$name,
in_ty, in_ty,
in_elem, in_elem,
ret_ty ret_ty
), }),
}; };
} }
}; };
@ -1686,22 +1679,20 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
let input = if !$boolean { let input = if !$boolean {
require!( require!(
ret_ty == in_elem, ret_ty == in_elem,
"expected return type `{}` (element of input `{}`), found `{}`", InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
in_elem,
in_ty,
ret_ty
); );
args[0].immediate() args[0].immediate()
} else { } else {
match in_elem.kind() { match in_elem.kind() {
ty::Int(_) | ty::Uint(_) => {} ty::Int(_) | ty::Uint(_) => {}
_ => return_error!( _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
"unsupported {} from `{}` with element `{}` to `{}`", span,
sym::$name, name,
symbol: sym::$name,
in_ty, in_ty,
in_elem, in_elem,
ret_ty ret_ty
), }),
} }
// boolean reductions operate on vectors of i1s: // boolean reductions operate on vectors of i1s:
@ -1714,13 +1705,14 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
let r = bx.$red(input); let r = bx.$red(input);
Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) }) Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
} }
_ => return_error!( _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
"unsupported {} from `{}` with element `{}` to `{}`", span,
sym::$name, name,
symbol: sym::$name,
in_ty, in_ty,
in_elem, in_elem,
ret_ty ret_ty
), }),
}; };
} }
}; };
@ -1733,16 +1725,18 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
bitwise_red!(simd_reduce_any: vector_reduce_or, true); bitwise_red!(simd_reduce_any: vector_reduce_or, true);
if name == sym::simd_cast_ptr { if name == sym::simd_cast_ptr {
require_simd!(ret_ty, "return"); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!( require!(
in_len == out_len, in_len == out_len,
"expected return type with length {} (same as input type `{}`), \ InvalidMonomorphization::ReturnLengthInputType {
found `{}` with length {}", span,
in_len, name,
in_ty, in_len,
ret_ty, in_ty,
out_len ret_ty,
out_len
}
); );
match in_elem.kind() { match in_elem.kind() {
@ -1751,9 +1745,14 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
}); });
assert!(!check_sized); // we are in codegen, so we shouldn't see these types assert!(!check_sized); // we are in codegen, so we shouldn't see these types
require!(metadata.is_unit(), "cannot cast fat pointer `{}`", in_elem) require!(
metadata.is_unit(),
InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
);
}
_ => {
return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
} }
_ => return_error!("expected pointer, got `{}`", in_elem),
} }
match out_elem.kind() { match out_elem.kind() {
ty::RawPtr(p) => { ty::RawPtr(p) => {
@ -1761,9 +1760,14 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
}); });
assert!(!check_sized); // we are in codegen, so we shouldn't see these types assert!(!check_sized); // we are in codegen, so we shouldn't see these types
require!(metadata.is_unit(), "cannot cast to fat pointer `{}`", out_elem) require!(
metadata.is_unit(),
InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }
);
}
_ => {
return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
} }
_ => return_error!("expected pointer, got `{}`", out_elem),
} }
if in_elem == out_elem { if in_elem == out_elem {
@ -1774,66 +1778,76 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
} }
if name == sym::simd_expose_addr { if name == sym::simd_expose_addr {
require_simd!(ret_ty, "return"); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!( require!(
in_len == out_len, in_len == out_len,
"expected return type with length {} (same as input type `{}`), \ InvalidMonomorphization::ReturnLengthInputType {
found `{}` with length {}", span,
in_len, name,
in_ty, in_len,
ret_ty, in_ty,
out_len ret_ty,
out_len
}
); );
match in_elem.kind() { match in_elem.kind() {
ty::RawPtr(_) => {} ty::RawPtr(_) => {}
_ => return_error!("expected pointer, got `{}`", in_elem), _ => {
return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
}
} }
match out_elem.kind() { match out_elem.kind() {
ty::Uint(ty::UintTy::Usize) => {} ty::Uint(ty::UintTy::Usize) => {}
_ => return_error!("expected `usize`, got `{}`", out_elem), _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: out_elem }),
} }
return Ok(bx.ptrtoint(args[0].immediate(), llret_ty)); return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
} }
if name == sym::simd_from_exposed_addr { if name == sym::simd_from_exposed_addr {
require_simd!(ret_ty, "return"); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!( require!(
in_len == out_len, in_len == out_len,
"expected return type with length {} (same as input type `{}`), \ InvalidMonomorphization::ReturnLengthInputType {
found `{}` with length {}", span,
in_len, name,
in_ty, in_len,
ret_ty, in_ty,
out_len ret_ty,
out_len
}
); );
match in_elem.kind() { match in_elem.kind() {
ty::Uint(ty::UintTy::Usize) => {} ty::Uint(ty::UintTy::Usize) => {}
_ => return_error!("expected `usize`, got `{}`", in_elem), _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: in_elem }),
} }
match out_elem.kind() { match out_elem.kind() {
ty::RawPtr(_) => {} ty::RawPtr(_) => {}
_ => return_error!("expected pointer, got `{}`", out_elem), _ => {
return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
}
} }
return Ok(bx.inttoptr(args[0].immediate(), llret_ty)); return Ok(bx.inttoptr(args[0].immediate(), llret_ty));
} }
if name == sym::simd_cast || name == sym::simd_as { if name == sym::simd_cast || name == sym::simd_as {
require_simd!(ret_ty, "return"); require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
require!( require!(
in_len == out_len, in_len == out_len,
"expected return type with length {} (same as input type `{}`), \ InvalidMonomorphization::ReturnLengthInputType {
found `{}` with length {}", span,
in_len, name,
in_ty, in_len,
ret_ty, in_ty,
out_len ret_ty,
out_len
}
); );
// casting cares about nominal type, not just structural type // casting cares about nominal type, not just structural type
if in_elem == out_elem { if in_elem == out_elem {
@ -1912,11 +1926,14 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
} }
require!( require!(
false, false,
"unsupported cast from `{}` with element `{}` to `{}` with element `{}`", InvalidMonomorphization::UnsupportedCast {
in_ty, span,
in_elem, name,
ret_ty, in_ty,
out_elem in_elem,
ret_ty,
out_elem
}
); );
} }
macro_rules! arith_binary { macro_rules! arith_binary {
@ -1928,10 +1945,10 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
})* })*
_ => {}, _ => {},
} }
require!(false, require!(
"unsupported operation on `{}` with element `{}`", false,
in_ty, InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
in_elem) );
})* })*
} }
} }
@ -1959,10 +1976,10 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
})* })*
_ => {}, _ => {},
} }
require!(false, require!(
"unsupported operation on `{}` with element `{}`", false,
in_ty, InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
in_elem) );
})* })*
} }
} }
@ -2000,12 +2017,12 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)), ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
_ => { _ => {
return_error!( return_error!(InvalidMonomorphization::ExpectedVectorElementType {
"expected element type `{}` of vector type `{}` \ span,
to be a signed or unsigned integer type", name,
arg_tys[0].simd_size_and_type(bx.tcx()).1, expected_element: arg_tys[0].simd_size_and_type(bx.tcx()).1,
arg_tys[0] vector_type: arg_tys[0]
); });
} }
}; };
let llvm_intrinsic = &format!( let llvm_intrinsic = &format!(

View file

@ -27,6 +27,7 @@ rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" } rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" } rustc_span = { path = "../rustc_span" }
rustc_middle = { path = "../rustc_middle" } rustc_middle = { path = "../rustc_middle" }
rustc_type_ir = { path = "../rustc_type_ir" }
rustc_attr = { path = "../rustc_attr" } rustc_attr = { path = "../rustc_attr" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_data_structures = { path = "../rustc_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" }

View file

@ -2616,7 +2616,7 @@ fn add_static_crate<'a>(
sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum); sess.target.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum);
let mut archive = archive_builder_builder.new_archive_builder(sess); let mut archive = archive_builder_builder.new_archive_builder(sess);
if let Err(e) = archive.add_archive( if let Err(error) = archive.add_archive(
cratepath, cratepath,
Box::new(move |f| { Box::new(move |f| {
if f == METADATA_FILENAME { if f == METADATA_FILENAME {
@ -2656,7 +2656,7 @@ fn add_static_crate<'a>(
false false
}), }),
) { ) {
sess.fatal(&format!("failed to build archive from rlib: {}", e)); sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
} }
if archive.build(&dst) { if archive.build(&dst) {
link_upstream(&dst); link_upstream(&dst);

View file

@ -5,6 +5,7 @@ use crate::back::write::{
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
}; };
use crate::common::{IntPredicate, RealPredicate, TypeKind}; use crate::common::{IntPredicate, RealPredicate, TypeKind};
use crate::errors;
use crate::meth; use crate::meth;
use crate::mir; use crate::mir;
use crate::mir::operand::OperandValue; use crate::mir::operand::OperandValue;
@ -451,10 +452,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let Some(llfn) = cx.declare_c_main(llfty) else { let Some(llfn) = cx.declare_c_main(llfty) else {
// FIXME: We should be smart and show a better diagnostic here. // FIXME: We should be smart and show a better diagnostic here.
let span = cx.tcx().def_span(rust_main_def_id); let span = cx.tcx().def_span(rust_main_def_id);
cx.sess() cx.sess().emit_err(errors::MultipleMainFunctions { span });
.struct_span_err(span, "entry symbol `main` declared multiple times")
.help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
.emit();
cx.sess().abort_if_errors(); cx.sess().abort_if_errors();
bug!(); bug!();
}; };
@ -595,8 +593,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
&metadata, &metadata,
&exported_symbols::metadata_symbol_name(tcx), &exported_symbols::metadata_symbol_name(tcx),
); );
if let Err(err) = std::fs::write(&file_name, data) { if let Err(error) = std::fs::write(&file_name, data) {
tcx.sess.fatal(&format!("error writing metadata object file: {}", err)); tcx.sess.emit_fatal(errors::MetadataObjectFileWrite { error });
} }
Some(CompiledModule { Some(CompiledModule {
name: metadata_cgu_name, name: metadata_cgu_name,
@ -815,11 +813,7 @@ impl CrateInfo {
let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
let windows_subsystem = subsystem.map(|subsystem| { let windows_subsystem = subsystem.map(|subsystem| {
if subsystem != sym::windows && subsystem != sym::console { if subsystem != sym::windows && subsystem != sym::console {
tcx.sess.fatal(&format!( tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
"invalid windows subsystem `{}`, only \
`windows` and `console` are allowed",
subsystem
));
} }
subsystem.to_string() subsystem.to_string()
}); });

View file

@ -1,10 +1,8 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use rustc_errors::struct_span_err;
use rustc_hir::LangItem; use rustc_hir::LangItem;
use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt}; use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
use rustc_session::Session;
use rustc_span::Span; use rustc_span::Span;
use crate::base; use crate::base;
@ -193,10 +191,6 @@ pub fn shift_mask_val<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
} }
} }
pub fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
struct_span_err!(a, b, E0511, "{}", c).emit();
}
pub fn asm_const_to_str<'tcx>( pub fn asm_const_to_str<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
sp: Span, sp: Span,

View file

@ -93,6 +93,7 @@ fn push_debuginfo_type_name<'tcx>(
Err(e) => { Err(e) => {
// Computing the layout can still fail here, e.g. if the target architecture // Computing the layout can still fail here, e.g. if the target architecture
// cannot represent the type. See https://github.com/rust-lang/rust/issues/94961. // cannot represent the type. See https://github.com/rust-lang/rust/issues/94961.
// FIXME: migrate once `rustc_middle::mir::interpret::InterpError` is translatable.
tcx.sess.fatal(&format!("{}", e)); tcx.sess.fatal(&format!("{}", e));
} }
} }

View file

@ -6,7 +6,9 @@ use rustc_errors::{
IntoDiagnosticArg, IntoDiagnosticArg,
}; };
use rustc_macros::Diagnostic; use rustc_macros::Diagnostic;
use rustc_middle::ty::Ty;
use rustc_span::{Span, Symbol}; use rustc_span::{Span, Symbol};
use rustc_type_ir::FloatTy;
use std::borrow::Cow; use std::borrow::Cow;
use std::io::Error; use std::io::Error;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -549,3 +551,432 @@ pub struct ExpectedUsedSymbol {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)]
#[diag(codegen_ssa_multiple_main_functions)]
#[help]
pub struct MultipleMainFunctions {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_metadata_object_file_write)]
pub struct MetadataObjectFileWrite {
pub error: Error,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_invalid_windows_subsystem)]
pub struct InvalidWindowsSubsystem {
pub subsystem: Symbol,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_erroneous_constant)]
pub struct ErroneousConstant {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_polymorphic_constant_too_generic)]
pub struct PolymorphicConstantTooGeneric {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_shuffle_indices_evaluation)]
pub struct ShuffleIndicesEvaluation {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_missing_memory_ordering)]
pub struct MissingMemoryOrdering;
#[derive(Diagnostic)]
#[diag(codegen_ssa_unknown_atomic_ordering)]
pub struct UnknownAtomicOrdering;
#[derive(Diagnostic)]
#[diag(codegen_ssa_atomic_compare_exchange)]
pub struct AtomicCompareExchange;
#[derive(Diagnostic)]
#[diag(codegen_ssa_unknown_atomic_operation)]
pub struct UnknownAtomicOperation;
#[derive(Diagnostic)]
pub enum InvalidMonomorphization<'tcx> {
#[diag(codegen_ssa_invalid_monomorphization_basic_integer_type, code = "E0511")]
BasicIntegerType {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_basic_float_type, code = "E0511")]
BasicFloatType {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_float_to_int_unchecked, code = "E0511")]
FloatToIntUnchecked {
#[primary_span]
span: Span,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_floating_point_vector, code = "E0511")]
FloatingPointVector {
#[primary_span]
span: Span,
name: Symbol,
f_ty: FloatTy,
in_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_floating_point_type, code = "E0511")]
FloatingPointType {
#[primary_span]
span: Span,
name: Symbol,
in_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_unrecognized_intrinsic, code = "E0511")]
UnrecognizedIntrinsic {
#[primary_span]
span: Span,
name: Symbol,
},
#[diag(codegen_ssa_invalid_monomorphization_simd_argument, code = "E0511")]
SimdArgument {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_simd_input, code = "E0511")]
SimdInput {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_simd_first, code = "E0511")]
SimdFirst {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_simd_second, code = "E0511")]
SimdSecond {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_simd_third, code = "E0511")]
SimdThird {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_simd_return, code = "E0511")]
SimdReturn {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_invalid_bitmask, code = "E0511")]
InvalidBitmask {
#[primary_span]
span: Span,
name: Symbol,
mask_ty: Ty<'tcx>,
expected_int_bits: u64,
expected_bytes: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_return_length_input_type, code = "E0511")]
ReturnLengthInputType {
#[primary_span]
span: Span,
name: Symbol,
in_len: u64,
in_ty: Ty<'tcx>,
ret_ty: Ty<'tcx>,
out_len: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_second_argument_length, code = "E0511")]
SecondArgumentLength {
#[primary_span]
span: Span,
name: Symbol,
in_len: u64,
in_ty: Ty<'tcx>,
arg_ty: Ty<'tcx>,
out_len: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_third_argument_length, code = "E0511")]
ThirdArgumentLength {
#[primary_span]
span: Span,
name: Symbol,
in_len: u64,
in_ty: Ty<'tcx>,
arg_ty: Ty<'tcx>,
out_len: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_return_integer_type, code = "E0511")]
ReturnIntegerType {
#[primary_span]
span: Span,
name: Symbol,
ret_ty: Ty<'tcx>,
out_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_simd_shuffle, code = "E0511")]
SimdShuffle {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_return_length, code = "E0511")]
ReturnLength {
#[primary_span]
span: Span,
name: Symbol,
in_len: u64,
ret_ty: Ty<'tcx>,
out_len: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_return_element, code = "E0511")]
ReturnElement {
#[primary_span]
span: Span,
name: Symbol,
in_elem: Ty<'tcx>,
in_ty: Ty<'tcx>,
ret_ty: Ty<'tcx>,
out_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_shuffle_index_not_constant, code = "E0511")]
ShuffleIndexNotConstant {
#[primary_span]
span: Span,
name: Symbol,
arg_idx: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds, code = "E0511")]
ShuffleIndexOutOfBounds {
#[primary_span]
span: Span,
name: Symbol,
arg_idx: u64,
total_len: u128,
},
#[diag(codegen_ssa_invalid_monomorphization_inserted_type, code = "E0511")]
InsertedType {
#[primary_span]
span: Span,
name: Symbol,
in_elem: Ty<'tcx>,
in_ty: Ty<'tcx>,
out_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_return_type, code = "E0511")]
ReturnType {
#[primary_span]
span: Span,
name: Symbol,
in_elem: Ty<'tcx>,
in_ty: Ty<'tcx>,
ret_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_expected_return_type, code = "E0511")]
ExpectedReturnType {
#[primary_span]
span: Span,
name: Symbol,
in_ty: Ty<'tcx>,
ret_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_mismatched_lengths, code = "E0511")]
MismatchedLengths {
#[primary_span]
span: Span,
name: Symbol,
m_len: u64,
v_len: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_mask_type, code = "E0511")]
MaskType {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = "E0511")]
VectorArgument {
#[primary_span]
span: Span,
name: Symbol,
in_ty: Ty<'tcx>,
in_elem: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = "E0511")]
CannotReturn {
#[primary_span]
span: Span,
name: Symbol,
ret_ty: Ty<'tcx>,
expected_int_bits: u64,
expected_bytes: u64,
},
#[diag(codegen_ssa_invalid_monomorphization_expected_element_type, code = "E0511")]
ExpectedElementType {
#[primary_span]
span: Span,
name: Symbol,
expected_element: Ty<'tcx>,
second_arg: Ty<'tcx>,
in_elem: Ty<'tcx>,
in_ty: Ty<'tcx>,
mutability: ExpectedPointerMutability,
},
#[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = "E0511")]
ThirdArgElementType {
#[primary_span]
span: Span,
name: Symbol,
expected_element: Ty<'tcx>,
third_arg: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = "E0511")]
UnsupportedSymbolOfSize {
#[primary_span]
span: Span,
name: Symbol,
symbol: Symbol,
in_ty: Ty<'tcx>,
in_elem: Ty<'tcx>,
size: u64,
ret_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol, code = "E0511")]
UnsupportedSymbol {
#[primary_span]
span: Span,
name: Symbol,
symbol: Symbol,
in_ty: Ty<'tcx>,
in_elem: Ty<'tcx>,
ret_ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_cast_fat_pointer, code = "E0511")]
CastFatPointer {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_expected_pointer, code = "E0511")]
ExpectedPointer {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_expected_usize, code = "E0511")]
ExpectedUsize {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_unsupported_cast, code = "E0511")]
UnsupportedCast {
#[primary_span]
span: Span,
name: Symbol,
in_ty: Ty<'tcx>,
in_elem: Ty<'tcx>,
ret_ty: Ty<'tcx>,
out_elem: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_unsupported_operation, code = "E0511")]
UnsupportedOperation {
#[primary_span]
span: Span,
name: Symbol,
in_ty: Ty<'tcx>,
in_elem: Ty<'tcx>,
},
#[diag(codegen_ssa_invalid_monomorphization_expected_vector_element_type, code = "E0511")]
ExpectedVectorElementType {
#[primary_span]
span: Span,
name: Symbol,
expected_element: Ty<'tcx>,
vector_type: Ty<'tcx>,
},
}
pub enum ExpectedPointerMutability {
Mut,
Not,
}
impl IntoDiagnosticArg for ExpectedPointerMutability {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
match self {
ExpectedPointerMutability::Mut => DiagnosticArgValue::Str(Cow::Borrowed("*mut")),
ExpectedPointerMutability::Not => DiagnosticArgValue::Str(Cow::Borrowed("*_")),
}
}
}

View file

@ -1,3 +1,4 @@
use crate::errors;
use crate::mir::operand::OperandRef; use crate::mir::operand::OperandRef;
use crate::traits::*; use crate::traits::*;
use rustc_middle::mir; use rustc_middle::mir;
@ -44,10 +45,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| { self.cx.tcx().const_eval_resolve(ty::ParamEnv::reveal_all(), uv, None).map_err(|err| {
match err { match err {
ErrorHandled::Reported(_) => { ErrorHandled::Reported(_) => {
self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered"); self.cx.tcx().sess.emit_err(errors::ErroneousConstant { span: constant.span });
} }
ErrorHandled::TooGeneric => { ErrorHandled::TooGeneric => {
span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err); self.cx
.tcx()
.sess
.diagnostic()
.emit_bug(errors::PolymorphicConstantTooGeneric { span: constant.span });
} }
} }
err err
@ -87,7 +92,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
(llval, c.ty()) (llval, c.ty())
}) })
.unwrap_or_else(|_| { .unwrap_or_else(|_| {
bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time"); bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span });
// We've errored, so we don't have to produce working code. // We've errored, so we don't have to produce working code.
let ty = self.monomorphize(ty); let ty = self.monomorphize(ty);
let llty = bx.backend_type(bx.layout_of(ty)); let llty = bx.backend_type(bx.layout_of(ty));

View file

@ -1,7 +1,9 @@
use super::operand::{OperandRef, OperandValue}; use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef; use super::place::PlaceRef;
use super::FunctionCx; use super::FunctionCx;
use crate::common::{span_invalid_monomorphization_error, IntPredicate}; use crate::common::IntPredicate;
use crate::errors;
use crate::errors::InvalidMonomorphization;
use crate::glue; use crate::glue;
use crate::meth; use crate::meth;
use crate::traits::*; use crate::traits::*;
@ -305,15 +307,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!(), _ => bug!(),
}, },
None => { None => {
span_invalid_monomorphization_error( bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
bx.tcx().sess,
span,
&format!(
"invalid monomorphization of `{}` intrinsic: \
expected basic integer type, found `{}`",
name, ty
),
);
return; return;
} }
} }
@ -329,15 +323,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
_ => bug!(), _ => bug!(),
}, },
None => { None => {
span_invalid_monomorphization_error( bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { span, name, ty: arg_tys[0] });
bx.tcx().sess,
span,
&format!(
"invalid monomorphization of `{}` intrinsic: \
expected basic float type, found `{}`",
name, arg_tys[0]
),
);
return; return;
} }
} }
@ -345,29 +331,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
sym::float_to_int_unchecked => { sym::float_to_int_unchecked => {
if float_type_width(arg_tys[0]).is_none() { if float_type_width(arg_tys[0]).is_none() {
span_invalid_monomorphization_error( bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: arg_tys[0] });
bx.tcx().sess,
span,
&format!(
"invalid monomorphization of `float_to_int_unchecked` \
intrinsic: expected basic float type, \
found `{}`",
arg_tys[0]
),
);
return; return;
} }
let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else { let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
span_invalid_monomorphization_error( bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: ret_ty });
bx.tcx().sess,
span,
&format!(
"invalid monomorphization of `float_to_int_unchecked` \
intrinsic: expected basic integer type, \
found `{}`",
ret_ty
),
);
return; return;
}; };
if signed { if signed {
@ -402,7 +370,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
use crate::common::{AtomicRmwBinOp, SynchronizationScope}; use crate::common::{AtomicRmwBinOp, SynchronizationScope};
let Some((instruction, ordering)) = atomic.split_once('_') else { let Some((instruction, ordering)) = atomic.split_once('_') else {
bx.sess().fatal("Atomic intrinsic missing memory ordering"); bx.sess().emit_fatal(errors::MissingMemoryOrdering);
}; };
let parse_ordering = |bx: &Bx, s| match s { let parse_ordering = |bx: &Bx, s| match s {
@ -412,25 +380,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
"release" => Release, "release" => Release,
"acqrel" => AcquireRelease, "acqrel" => AcquireRelease,
"seqcst" => SequentiallyConsistent, "seqcst" => SequentiallyConsistent,
_ => bx.sess().fatal("unknown ordering in atomic intrinsic"), _ => bx.sess().emit_fatal(errors::UnknownAtomicOrdering),
}; };
let invalid_monomorphization = |ty| { let invalid_monomorphization = |ty| {
span_invalid_monomorphization_error( bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
bx.tcx().sess,
span,
&format!(
"invalid monomorphization of `{}` intrinsic: \
expected basic integer type, found `{}`",
name, ty
),
);
}; };
match instruction { match instruction {
"cxchg" | "cxchgweak" => { "cxchg" | "cxchgweak" => {
let Some((success, failure)) = ordering.split_once('_') else { let Some((success, failure)) = ordering.split_once('_') else {
bx.sess().fatal("Atomic compare-exchange intrinsic missing failure memory ordering"); bx.sess().emit_fatal(errors::AtomicCompareExchange);
}; };
let ty = substs.type_at(0); let ty = substs.type_at(0);
if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() { if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
@ -529,7 +489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
"min" => AtomicRmwBinOp::AtomicMin, "min" => AtomicRmwBinOp::AtomicMin,
"umax" => AtomicRmwBinOp::AtomicUMax, "umax" => AtomicRmwBinOp::AtomicUMax,
"umin" => AtomicRmwBinOp::AtomicUMin, "umin" => AtomicRmwBinOp::AtomicUMin,
_ => bx.sess().fatal("unknown atomic operation"), _ => bx.sess().emit_fatal(errors::UnknownAtomicOperation),
}; };
let ty = substs.type_at(0); let ty = substs.type_at(0);

View file

@ -192,3 +192,102 @@ codegen_ssa_unknown_archive_kind =
Don't know how to build archive of type: {$kind} Don't know how to build archive of type: {$kind}
codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
.help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
codegen_ssa_erroneous_constant = erroneous constant encountered
codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
codegen_ssa_unknown_atomic_operation = unknown atomic operation
codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}`
codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}`
codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type
codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}`
codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}`
codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}`
codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}`
codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type

View file

@ -172,3 +172,142 @@ infer_msl_unmet_req = because this has an unmet lifetime requirement
infer_msl_trait_note = this has an implicit `'static` lifetime requirement infer_msl_trait_note = this has an implicit `'static` lifetime requirement
infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
infer_suggest_add_let_for_letchains = consider adding `let` infer_suggest_add_let_for_letchains = consider adding `let`
infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
.label = lifetime `{$named}` required
infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
.label = lifetime `{$named}` required
infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
[true] ...
*[false] {""}
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
[true] ...
*[false] {""}
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
[true] ...
*[false] {""}
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
[true] ...
*[false] {""}
}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`...
infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`...
infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$ty_or_sig}` must implement `{$trait_path}`
infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
[true] , for some specific lifetime `'{$lifetime}`
*[false] {""}
}
infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
[true] , for some specific lifetime `'{$lifetime}`
*[false] {""}
}
infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
[true] , for some specific lifetime `'{$lifetime}`
*[false] {""}
}
infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
.label_satisfy = doesn't satisfy where-clause
.label_where = due to a where-clause on `{$def_id}`...
.label_dup = implementation of `{$trait_def_id}` is not general enough
infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
.found = found `{$found}`
.expected = expected `{$expected}`
.expected_found = expected `{$expected}`
{" "}found `{$found}`
infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement
infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
infer_but_calling_introduces = {$has_param_name ->
[true] `{$param_name}`
*[false] `fn` parameter
} has {$lifetime_kind ->
[named] lifetime `{lifetime}`
*[anon] an anonymous lifetime `'_`
} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement
.label1 = {$has_lifetime ->
[named] lifetime `{lifetime}`
*[anon] an anonymous lifetime `'_`
}
.label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path ->
[named] `impl` of `{$impl_path}`
*[anon] inherent `impl`
}
infer_but_needs_to_satisfy = {$has_param_name ->
[true] `{$param_name}`
*[false] `fn` parameter
} has {$has_lifetime ->
[named] lifetime `{lifetime}`
*[anon] an anonymous lifetime `'_`
} but it needs to satisfy a `'static` lifetime requirement
.influencer = this data with {$has_lifetime ->
[named] lifetime `{lifetime}`
*[anon] an anonymous lifetime `'_`
}...
.require = {$spans_empty ->
*[true] ...is used and required to live as long as `'static` here
[false] ...and is required to live as long as `'static` here
}
.used_here = ...is used here...
.introduced_by_bound = 'static` lifetime requirement introduced by this bound
infer_more_targeted = {$has_param_name ->
[true] `{$param_name}`
*[false] `fn` parameter
} has {$has_lifetime ->
[named] lifetime `{lifetime}`
*[anon] an anonymous lifetime `'_`
} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
infer_ril_introduced_here = `'static` requirement introduced here
infer_ril_introduced_by = requirement introduced by this return type
infer_ril_because_of = because of this returned expression
infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type

View file

@ -17,6 +17,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_target = { path = "../rustc_target" } rustc_target = { path = "../rustc_target" }
rustc_hir = { path = "../rustc_hir" } rustc_hir = { path = "../rustc_hir" }
rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_type_ir = { path = "../rustc_type_ir" }
unicode-width = "0.1.4" unicode-width = "0.1.4"
termcolor = "1.0" termcolor = "1.0"
annotate-snippets = "0.9" annotate-snippets = "0.9"

View file

@ -1,7 +1,7 @@
use crate::diagnostic::IntoDiagnosticArg; use crate::diagnostic::IntoDiagnosticArg;
use crate::{ use crate::{
Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed, Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed,
SubdiagnosticMessage, ExplicitBug, SubdiagnosticMessage,
}; };
use crate::{Handler, Level, MultiSpan, StashKey}; use crate::{Handler, Level, MultiSpan, StashKey};
use rustc_lint_defs::Applicability; use rustc_lint_defs::Applicability;
@ -12,6 +12,7 @@ use std::borrow::Cow;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::panic;
use std::thread::panicking; use std::thread::panicking;
/// Trait implemented by error types. This should not be implemented manually. Instead, use /// Trait implemented by error types. This should not be implemented manually. Instead, use
@ -308,6 +309,58 @@ impl EmissionGuarantee for Noted {
} }
} }
/// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
/// bug struct diagnostics.
#[derive(Copy, Clone)]
pub struct Bug;
impl<'a> DiagnosticBuilder<'a, Bug> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
#[track_caller]
pub(crate) fn new_bug(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message);
Self::new_diagnostic_bug(handler, diagnostic)
}
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
pub(crate) fn new_diagnostic_bug(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic bug");
Self {
inner: DiagnosticBuilderInner {
state: DiagnosticBuilderState::Emittable(handler),
diagnostic: Box::new(diagnostic),
},
_marker: PhantomData,
}
}
}
impl EmissionGuarantee for Bug {
fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
match db.inner.state {
// First `.emit()` call, the `&Handler` is still available.
DiagnosticBuilderState::Emittable(handler) => {
db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
handler.emit_diagnostic(&mut db.inner.diagnostic);
}
// `.emit()` was previously called, disallowed from repeating it.
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
}
// Then panic. No need to return the marker type.
panic::panic_any(ExplicitBug);
}
fn make_diagnostic_builder(
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, Self> {
DiagnosticBuilder::new_bug(handler, msg)
}
}
impl<'a> DiagnosticBuilder<'a, !> { impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the /// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`]. /// `struct_*` methods on [`Handler`].

View file

@ -9,6 +9,7 @@ use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
use rustc_target::abi::TargetDataLayoutErrors; use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
use rustc_type_ir as type_ir;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use std::num::ParseIntError; use std::num::ParseIntError;
@ -170,6 +171,12 @@ impl IntoDiagnosticArg for ast::token::TokenKind {
} }
} }
impl IntoDiagnosticArg for type_ir::FloatTy {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Borrowed(self.name_str()))
}
}
impl IntoDiagnosticArg for Level { impl IntoDiagnosticArg for Level {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Borrowed(match self { DiagnosticArgValue::Str(Cow::Borrowed(match self {

View file

@ -1133,6 +1133,20 @@ impl Handler {
self.create_fatal(fatal).emit() self.create_fatal(fatal).emit()
} }
pub fn create_bug<'a>(
&'a self,
bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
) -> DiagnosticBuilder<'a, diagnostic_builder::Bug> {
bug.into_diagnostic(self)
}
pub fn emit_bug<'a>(
&'a self,
bug: impl IntoDiagnostic<'a, diagnostic_builder::Bug>,
) -> diagnostic_builder::Bug {
self.create_bug(bug).emit()
}
fn emit_diag_at_span( fn emit_diag_at_span(
&self, &self,
mut diag: Diagnostic, mut diag: Diagnostic,

View file

@ -1,15 +1,18 @@
use hir::GenericParamKind; use hir::GenericParamKind;
use rustc_errors::{ use rustc_errors::{
fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
MultiSpan, SubdiagnosticMessage, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage,
}; };
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::{FnRetTy, Ty}; use rustc_hir::FnRetTy;
use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::{Region, TyCtxt}; use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt};
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use rustc_span::Symbol;
use rustc_span::{symbol::Ident, BytePos, Span}; use rustc_span::{symbol::Ident, BytePos, Span};
use crate::infer::error_reporting::nice_region_error::placeholder_error::Highlighted;
use crate::infer::error_reporting::{ use crate::infer::error_reporting::{
need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind}, need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
ObligationCauseAsDiagArg, ObligationCauseAsDiagArg,
@ -357,8 +360,8 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
pub struct AddLifetimeParamsSuggestion<'a> { pub struct AddLifetimeParamsSuggestion<'a> {
pub tcx: TyCtxt<'a>, pub tcx: TyCtxt<'a>,
pub sub: Region<'a>, pub sub: Region<'a>,
pub ty_sup: &'a Ty<'a>, pub ty_sup: &'a hir::Ty<'a>,
pub ty_sub: &'a Ty<'a>, pub ty_sub: &'a hir::Ty<'a>,
pub add_note: bool, pub add_note: bool,
} }
@ -520,3 +523,411 @@ pub struct MismatchedStaticLifetime<'a> {
#[subdiagnostic] #[subdiagnostic]
pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>, pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
} }
#[derive(Diagnostic)]
pub enum ExplicitLifetimeRequired<'a> {
#[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")]
WithIdent {
#[primary_span]
#[label]
span: Span,
simple_ident: Ident,
named: String,
#[suggestion(
infer_explicit_lifetime_required_sugg_with_ident,
code = "{new_ty}",
applicability = "unspecified"
)]
new_ty_span: Span,
#[skip_arg]
new_ty: Ty<'a>,
},
#[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")]
WithParamType {
#[primary_span]
#[label]
span: Span,
named: String,
#[suggestion(
infer_explicit_lifetime_required_sugg_with_param_type,
code = "{new_ty}",
applicability = "unspecified"
)]
new_ty_span: Span,
#[skip_arg]
new_ty: Ty<'a>,
},
}
pub enum TyOrSig<'tcx> {
Ty(Highlighted<'tcx, Ty<'tcx>>),
ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
}
impl IntoDiagnosticArg for TyOrSig<'_> {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
match self {
TyOrSig::Ty(ty) => ty.into_diagnostic_arg(),
TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(),
}
}
}
#[derive(Subdiagnostic)]
pub enum ActualImplExplNotes<'tcx> {
#[note(infer_actual_impl_expl_expected_signature_two)]
ExpectedSignatureTwo {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
lifetime_2: usize,
},
#[note(infer_actual_impl_expl_expected_signature_any)]
ExpectedSignatureAny {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
},
#[note(infer_actual_impl_expl_expected_signature_some)]
ExpectedSignatureSome {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
},
#[note(infer_actual_impl_expl_expected_signature_nothing)]
ExpectedSignatureNothing {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
},
#[note(infer_actual_impl_expl_expected_passive_two)]
ExpectedPassiveTwo {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
lifetime_2: usize,
},
#[note(infer_actual_impl_expl_expected_passive_any)]
ExpectedPassiveAny {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
},
#[note(infer_actual_impl_expl_expected_passive_some)]
ExpectedPassiveSome {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
},
#[note(infer_actual_impl_expl_expected_passive_nothing)]
ExpectedPassiveNothing {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
},
#[note(infer_actual_impl_expl_expected_other_two)]
ExpectedOtherTwo {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
lifetime_2: usize,
},
#[note(infer_actual_impl_expl_expected_other_any)]
ExpectedOtherAny {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
},
#[note(infer_actual_impl_expl_expected_other_some)]
ExpectedOtherSome {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
},
#[note(infer_actual_impl_expl_expected_other_nothing)]
ExpectedOtherNothing {
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
},
#[note(infer_actual_impl_expl_but_actually_implements_trait)]
ButActuallyImplementsTrait {
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
has_lifetime: bool,
lifetime: usize,
},
#[note(infer_actual_impl_expl_but_actually_implemented_for_ty)]
ButActuallyImplementedForTy {
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
has_lifetime: bool,
lifetime: usize,
ty: String,
},
#[note(infer_actual_impl_expl_but_actually_ty_implements)]
ButActuallyTyImplements {
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
has_lifetime: bool,
lifetime: usize,
ty: String,
},
}
pub enum ActualImplExpectedKind {
Signature,
Passive,
Other,
}
pub enum ActualImplExpectedLifetimeKind {
Two,
Any,
Some,
Nothing,
}
impl<'tcx> ActualImplExplNotes<'tcx> {
pub fn new_expected(
kind: ActualImplExpectedKind,
lt_kind: ActualImplExpectedLifetimeKind,
leading_ellipsis: bool,
ty_or_sig: TyOrSig<'tcx>,
trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
lifetime_1: usize,
lifetime_2: usize,
) -> Self {
match (kind, lt_kind) {
(ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
Self::ExpectedSignatureTwo {
leading_ellipsis,
ty_or_sig,
trait_path,
lifetime_1,
lifetime_2,
}
}
(ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
}
(ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
}
(ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
}
(ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
Self::ExpectedPassiveTwo {
leading_ellipsis,
ty_or_sig,
trait_path,
lifetime_1,
lifetime_2,
}
}
(ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
}
(ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
}
(ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
}
(ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
Self::ExpectedOtherTwo {
leading_ellipsis,
ty_or_sig,
trait_path,
lifetime_1,
lifetime_2,
}
}
(ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
}
(ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
}
(ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
}
}
}
}
#[derive(Diagnostic)]
#[diag(infer_trait_placeholder_mismatch)]
pub struct TraitPlaceholderMismatch<'tcx> {
#[primary_span]
pub span: Span,
#[label(label_satisfy)]
pub satisfy_span: Option<Span>,
#[label(label_where)]
pub where_span: Option<Span>,
#[label(label_dup)]
pub dup_span: Option<Span>,
pub def_id: String,
pub trait_def_id: String,
#[subdiagnostic]
pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
}
pub struct ConsiderBorrowingParamHelp {
pub spans: Vec<Span>,
}
impl AddToDiagnostic for ConsiderBorrowingParamHelp {
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
let mut type_param_span: MultiSpan = self.spans.clone().into();
for &span in &self.spans {
// Seems like we can't call f() here as Into<DiagnosticMessage> is required
type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing);
}
let msg = f(diag, fluent::infer_tid_param_help.into());
diag.span_help(type_param_span, msg);
}
}
#[derive(Subdiagnostic)]
#[help(infer_tid_rel_help)]
pub struct RelationshipHelp;
#[derive(Diagnostic)]
#[diag(infer_trait_impl_diff)]
pub struct TraitImplDiff {
#[primary_span]
#[label(found)]
pub sp: Span,
#[label(expected)]
pub trait_sp: Span,
#[note(expected_found)]
pub note: (),
#[subdiagnostic]
pub param_help: ConsiderBorrowingParamHelp,
#[subdiagnostic]
// Seems like subdiagnostics are always pushed to the end, so this one
// also has to be a subdiagnostic to maintain order.
pub rel_help: Option<RelationshipHelp>,
pub expected: String,
pub found: String,
}
pub struct DynTraitConstraintSuggestion {
pub span: Span,
pub ident: Ident,
}
impl AddToDiagnostic for DynTraitConstraintSuggestion {
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
let mut multi_span: MultiSpan = vec![self.span].into();
multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement);
let msg = f(diag, fluent::infer_dtcs_has_req_note.into());
diag.span_note(multi_span, msg);
let msg = f(diag, fluent::infer_dtcs_suggestion.into());
diag.span_suggestion_verbose(
self.span.shrink_to_hi(),
msg,
" + '_",
Applicability::MaybeIncorrect,
);
}
}
#[derive(Diagnostic)]
#[diag(infer_but_calling_introduces, code = "E0772")]
pub struct ButCallingIntroduces {
#[label(label1)]
pub param_ty_span: Span,
#[primary_span]
#[label(label2)]
pub cause_span: Span,
pub has_param_name: bool,
pub param_name: String,
pub has_lifetime: bool,
pub lifetime: String,
pub assoc_item: Symbol,
pub has_impl_path: bool,
pub impl_path: String,
}
pub struct ReqIntroducedLocations {
pub span: MultiSpan,
pub spans: Vec<Span>,
pub fn_decl_span: Span,
pub cause_span: Span,
pub add_label: bool,
}
impl AddToDiagnostic for ReqIntroducedLocations {
fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, f: F)
where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
for sp in self.spans {
self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
}
if self.add_label {
self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by);
}
self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of);
let msg = f(diag, fluent::infer_ril_static_introduced_by.into());
diag.span_note(self.span, msg);
}
}
pub struct MoreTargeted {
pub ident: Symbol,
}
impl AddToDiagnostic for MoreTargeted {
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _f: F)
where
F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
{
diag.code(rustc_errors::error_code!(E0772));
diag.set_primary_message(fluent::infer_more_targeted);
diag.set_arg("ident", self.ident);
}
}
#[derive(Diagnostic)]
#[diag(infer_but_needs_to_satisfy, code = "E0759")]
pub struct ButNeedsToSatisfy {
#[primary_span]
pub sp: Span,
#[label(influencer)]
pub influencer_point: Span,
#[label(used_here)]
pub spans: Vec<Span>,
#[label(require)]
pub require_span_as_label: Option<Span>,
#[note(require)]
pub require_span_as_note: Option<Span>,
#[note(introduced_by_bound)]
pub bound: Option<Span>,
#[subdiagnostic]
pub req_introduces_loc: Option<ReqIntroducedLocations>,
pub spans_empty: bool,
pub has_lifetime: bool,
pub lifetime: String,
}

View file

@ -9,7 +9,7 @@ mod different_lifetimes;
pub mod find_anon_type; pub mod find_anon_type;
mod mismatched_static_lifetime; mod mismatched_static_lifetime;
mod named_anon_conflict; mod named_anon_conflict;
mod placeholder_error; pub(crate) mod placeholder_error;
mod placeholder_relation; mod placeholder_relation;
mod static_impl_trait; mod static_impl_trait;
mod trait_impl_difference; mod trait_impl_difference;

View file

@ -1,8 +1,11 @@
//! Error Reporting for Anonymous Region Lifetime Errors //! Error Reporting for Anonymous Region Lifetime Errors
//! where one region is named and the other is anonymous. //! where one region is named and the other is anonymous.
use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use crate::{
errors::ExplicitLifetimeRequired,
infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
};
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
@ -86,31 +89,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
{ {
return None; return None;
} }
let named = named.to_string();
let (error_var, span_label_var) = match param.pat.simple_ident() { let err = match param.pat.simple_ident() {
Some(simple_ident) => ( Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
format!("the type of `{}`", simple_ident), span,
format!("the type of `{}`", simple_ident), simple_ident,
), named,
None => ("parameter type".to_owned(), "type".to_owned()), new_ty_span,
new_ty,
},
None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
}; };
Some(self.tcx().sess.parse_sess.create_err(err))
let mut diag = struct_span_err!(
self.tcx().sess,
span,
E0621,
"explicit lifetime required in {}",
error_var
);
diag.span_label(span, format!("lifetime `{}` required", named));
diag.span_suggestion(
new_ty_span,
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
new_ty,
Applicability::Unspecified,
);
Some(diag)
} }
} }

View file

@ -1,10 +1,14 @@
use crate::errors::{
ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
TraitPlaceholderMismatch, TyOrSig,
};
use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::ValuePairs; use crate::infer::ValuePairs;
use crate::infer::{SubregionOrigin, TypeTrace}; use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_hir::def::Namespace; use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::ExpectedFound;
@ -12,7 +16,43 @@ use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt}; use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
use std::fmt::{self, Write}; use std::fmt;
// HACK(eddyb) maybe move this in a more central location.
#[derive(Copy, Clone)]
pub struct Highlighted<'tcx, T> {
tcx: TyCtxt<'tcx>,
highlight: RegionHighlightMode<'tcx>,
value: T,
}
impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
where
T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
{
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
}
}
impl<'tcx, T> Highlighted<'tcx, T> {
fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
}
}
impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
where
T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
printer.region_highlight_mode = self.highlight;
let s = self.value.print(printer)?.into_buffer();
f.write_str(&s)
}
}
impl<'tcx> NiceRegionError<'_, 'tcx> { impl<'tcx> NiceRegionError<'_, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and /// When given a `ConcreteFailure` for a function with arguments containing a named region and
@ -205,26 +245,21 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_substs: SubstsRef<'tcx>, actual_substs: SubstsRef<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let span = cause.span(); let span = cause.span();
let msg = format!(
"implementation of `{}` is not general enough",
self.tcx().def_path_str(trait_def_id),
);
let mut err = self.tcx().sess.struct_span_err(span, &msg);
let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
| ObligationCauseCode::ExprItemObligation(def_id, ..) = if let ObligationCauseCode::ItemObligation(def_id)
*cause.code() | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
{ {
err.span_label(span, "doesn't satisfy where-clause"); (
err.span_label( true,
self.tcx().def_span(def_id), Some(span),
&format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)), Some(self.tcx().def_span(def_id)),
); None,
true self.tcx().def_path_str(def_id),
} else { )
err.span_label(span, &msg); } else {
false (false, None, None, Some(span), String::new())
}; };
let expected_trait_ref = self let expected_trait_ref = self
.cx .cx
@ -284,8 +319,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
?expected_self_ty_has_vid, ?expected_self_ty_has_vid,
); );
self.explain_actual_impl_that_was_found( let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
&mut err,
sub_placeholder, sub_placeholder,
sup_placeholder, sup_placeholder,
has_sub, has_sub,
@ -299,7 +333,15 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
leading_ellipsis, leading_ellipsis,
); );
err self.tcx().sess.create_err(TraitPlaceholderMismatch {
span,
satisfy_span,
where_span,
dup_span,
def_id,
trait_def_id: self.tcx().def_path_str(trait_def_id),
actual_impl_expl_notes,
})
} }
/// Add notes with details about the expected and actual trait refs, with attention to cases /// Add notes with details about the expected and actual trait refs, with attention to cases
@ -309,7 +351,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
/// due to the number of combinations we have to deal with. /// due to the number of combinations we have to deal with.
fn explain_actual_impl_that_was_found( fn explain_actual_impl_that_was_found(
&self, &self,
err: &mut Diagnostic,
sub_placeholder: Option<Region<'tcx>>, sub_placeholder: Option<Region<'tcx>>,
sup_placeholder: Option<Region<'tcx>>, sup_placeholder: Option<Region<'tcx>>,
has_sub: Option<usize>, has_sub: Option<usize>,
@ -321,39 +362,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
actual_has_vid: Option<usize>, actual_has_vid: Option<usize>,
any_self_ty_has_vid: bool, any_self_ty_has_vid: bool,
leading_ellipsis: bool, leading_ellipsis: bool,
) { ) -> Vec<ActualImplExplNotes<'tcx>> {
// HACK(eddyb) maybe move this in a more central location.
#[derive(Copy, Clone)]
struct Highlighted<'tcx, T> {
tcx: TyCtxt<'tcx>,
highlight: RegionHighlightMode<'tcx>,
value: T,
}
impl<'tcx, T> Highlighted<'tcx, T> {
fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
}
}
impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
where
T: for<'a> Print<
'tcx,
FmtPrinter<'a, 'tcx>,
Error = fmt::Error,
Output = FmtPrinter<'a, 'tcx>,
>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
printer.region_highlight_mode = self.highlight;
let s = self.value.print(printer)?.into_buffer();
f.write_str(&s)
}
}
// The weird thing here with the `maybe_highlighting_region` calls and the // The weird thing here with the `maybe_highlighting_region` calls and the
// the match inside is meant to be like this: // the match inside is meant to be like this:
// //
@ -380,120 +389,110 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref); let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub); expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup); expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
err.note(&{
let passive_voice = match (has_sub, has_sup) {
(Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
(None, None) => {
expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
match expected_has_vid {
Some(_) => true,
None => any_self_ty_has_vid,
}
}
};
let mut note = if same_self_type { let passive_voice = match (has_sub, has_sup) {
let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); (None, None) => {
expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
if self_ty.value.is_closure() match expected_has_vid {
&& self.tcx().is_fn_trait(expected_trait_ref.value.def_id) Some(_) => true,
{ None => any_self_ty_has_vid,
let closure_sig = self_ty.map(|closure| {
if let ty::Closure(_, substs) = closure.kind() {
self.tcx().signature_unclosure(
substs.as_closure().sig(),
rustc_hir::Unsafety::Normal,
)
} else {
bug!("type is not longer closure");
}
});
format!(
"{}closure with signature `{}` must implement `{}`",
if leading_ellipsis { "..." } else { "" },
closure_sig,
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
} else {
format!(
"{}`{}` must implement `{}`",
if leading_ellipsis { "..." } else { "" },
self_ty,
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
}
} else if passive_voice {
format!(
"{}`{}` would have to be implemented for the type `{}`",
if leading_ellipsis { "..." } else { "" },
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
expected_trait_ref.map(|tr| tr.self_ty()),
)
} else {
format!(
"{}`{}` must implement `{}`",
if leading_ellipsis { "..." } else { "" },
expected_trait_ref.map(|tr| tr.self_ty()),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
};
match (has_sub, has_sup) {
(Some(n1), Some(n2)) => {
let _ = write!(
note,
", for any two lifetimes `'{}` and `'{}`...",
std::cmp::min(n1, n2),
std::cmp::max(n1, n2),
);
}
(Some(n), _) | (_, Some(n)) => {
let _ = write!(note, ", for any lifetime `'{}`...", n,);
}
(None, None) => {
if let Some(n) = expected_has_vid {
let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
}
} }
} }
};
note let (kind, ty_or_sig, trait_path) = if same_self_type {
}); let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
{
let closure_sig = self_ty.map(|closure| {
if let ty::Closure(_, substs) = closure.kind() {
self.tcx().signature_unclosure(
substs.as_closure().sig(),
rustc_hir::Unsafety::Normal,
)
} else {
bug!("type is not longer closure");
}
});
(
ActualImplExpectedKind::Signature,
TyOrSig::ClosureSig(closure_sig),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
} else {
(
ActualImplExpectedKind::Other,
TyOrSig::Ty(self_ty),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
}
} else if passive_voice {
(
ActualImplExpectedKind::Passive,
TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
} else {
(
ActualImplExpectedKind::Other,
TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
expected_trait_ref.map(|tr| tr.print_only_trait_path()),
)
};
let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
(Some(n1), Some(n2)) => {
(ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
}
(Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
(None, None) => {
if let Some(n) = expected_has_vid {
(ActualImplExpectedLifetimeKind::Some, n, 0)
} else {
(ActualImplExpectedLifetimeKind::Nothing, 0, 0)
}
}
};
let note_1 = ActualImplExplNotes::new_expected(
kind,
lt_kind,
leading_ellipsis,
ty_or_sig,
trait_path,
lifetime_1,
lifetime_2,
);
let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref); let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid); actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
err.note(&{
let passive_voice = match actual_has_vid {
Some(_) => any_self_ty_has_vid,
None => true,
};
let mut note = if same_self_type { let passive_voice = match actual_has_vid {
format!( Some(_) => any_self_ty_has_vid,
"...but it actually implements `{}`", None => true,
actual_trait_ref.map(|tr| tr.print_only_trait_path()), };
)
} else if passive_voice {
format!(
"...but `{}` is actually implemented for the type `{}`",
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
actual_trait_ref.map(|tr| tr.self_ty()),
)
} else {
format!(
"...but `{}` actually implements `{}`",
actual_trait_ref.map(|tr| tr.self_ty()),
actual_trait_ref.map(|tr| tr.print_only_trait_path()),
)
};
if let Some(n) = actual_has_vid { let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
let _ = write!(note, ", for some specific lifetime `'{}`", n); let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
let has_lifetime = actual_has_vid.is_some();
let lifetime = actual_has_vid.unwrap_or_default();
let note_2 = if same_self_type {
ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
} else if passive_voice {
ActualImplExplNotes::ButActuallyImplementedForTy {
trait_path,
ty,
has_lifetime,
lifetime,
} }
} else {
ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
};
note vec![note_1, note_2]
});
} }
} }

View file

@ -1,11 +1,15 @@
//! Error Reporting for static impl Traits. //! Error Reporting for static impl Traits.
use crate::errors::{
ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
ReqIntroducedLocations,
};
use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace}; use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{ use rustc_hir::{
@ -53,46 +57,32 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} }
let param = self.find_param_with_region(*sup_r, *sub_r)?; let param = self.find_param_with_region(*sup_r, *sub_r)?;
let lifetime = if sup_r.has_name() { let simple_ident = param.param.pat.simple_ident();
format!("lifetime `{}`", sup_r)
} else { let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
"an anonymous lifetime `'_`".to_string() AssocItemContainer::TraitContainer => {
let id = ctxt.assoc_item.container_id(tcx);
(true, tcx.def_path_str(id))
}
AssocItemContainer::ImplContainer => (false, String::new()),
}; };
let mut err = struct_span_err!(
tcx.sess, let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
cause.span, param_ty_span: param.param_ty_span,
E0772, cause_span: cause.span,
"{} has {} but calling `{}` introduces an implicit `'static` lifetime \ has_param_name: simple_ident.is_some(),
requirement", param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
param has_lifetime: sup_r.has_name(),
.param lifetime: sup_r.to_string(),
.pat assoc_item: ctxt.assoc_item.name,
.simple_ident() has_impl_path,
.map(|s| format!("`{}`", s)) impl_path,
.unwrap_or_else(|| "`fn` parameter".to_string()), });
lifetime,
ctxt.assoc_item.name,
);
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
err.span_label(
cause.span,
&format!(
"...is used and required to live as long as `'static` here \
because of an implicit lifetime bound on the {}",
match ctxt.assoc_item.container {
AssocItemContainer::TraitContainer => {
let id = ctxt.assoc_item.container_id(tcx);
format!("`impl` of `{}`", tcx.def_path_str(id))
}
AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
},
),
);
if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
let reported = err.emit(); let reported = err.emit();
return Some(reported); return Some(reported);
} else { } else {
err.cancel(); err.cancel()
} }
} }
return None; return None;
@ -108,25 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let sp = var_origin.span(); let sp = var_origin.span();
let return_sp = sub_origin.span(); let return_sp = sub_origin.span();
let param = self.find_param_with_region(*sup_r, *sub_r)?; let param = self.find_param_with_region(*sup_r, *sub_r)?;
let (lifetime_name, lifetime) = if sup_r.has_name() { let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
(sup_r.to_string(), format!("lifetime `{}`", sup_r))
} else {
("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
};
let param_name = param
.param
.pat
.simple_ident()
.map(|s| format!("`{}`", s))
.unwrap_or_else(|| "`fn` parameter".to_string());
let mut err = struct_span_err!(
tcx.sess,
sp,
E0759,
"{} has {} but it needs to satisfy a `'static` lifetime requirement",
param_name,
lifetime,
);
let (mention_influencer, influencer_point) = let (mention_influencer, influencer_point) =
if sup_origin.span().overlaps(param.param_ty_span) { if sup_origin.span().overlaps(param.param_ty_span) {
@ -145,7 +117,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} else { } else {
(!sup_origin.span().overlaps(return_sp), param.param_ty_span) (!sup_origin.span().overlaps(return_sp), param.param_ty_span)
}; };
err.span_label(influencer_point, &format!("this data with {}...", lifetime));
debug!("try_report_static_impl_trait: param_info={:?}", param); debug!("try_report_static_impl_trait: param_info={:?}", param);
@ -159,31 +130,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
spans.dedup_by_key(|span| (span.lo(), span.hi())); spans.dedup_by_key(|span| (span.lo(), span.hi()));
// We try to make the output have fewer overlapping spans if possible. // We try to make the output have fewer overlapping spans if possible.
let require_msg = if spans.is_empty() {
"...is used and required to live as long as `'static` here"
} else {
"...and is required to live as long as `'static` here"
};
let require_span = let require_span =
if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp }; if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
for span in &spans { let spans_empty = spans.is_empty();
err.span_label(*span, "...is used here..."); let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
} let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
Some(*bound)
if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
// If any of the "captured here" labels appears on the same line or after
// `require_span`, we put it on a note to ensure the text flows by appearing
// always at the end.
err.span_note(require_span, require_msg);
} else { } else {
// We don't need a note, it's already at the end, it can be shown as a `span_label`. None
err.span_label(require_span, require_msg); };
}
let mut subdiag = None;
if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
}
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
if let ObligationCauseCode::ReturnValue(hir_id) if let ObligationCauseCode::ReturnValue(hir_id)
| ObligationCauseCode::BlockTailExpression(hir_id) = cause.code() | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
@ -191,33 +150,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let parent_id = tcx.hir().get_parent_item(*hir_id); let parent_id = tcx.hir().get_parent_item(*hir_id);
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) { if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
let mut span: MultiSpan = fn_decl.output.span().into(); let mut span: MultiSpan = fn_decl.output.span().into();
let mut spans = Vec::new();
let mut add_label = true; let mut add_label = true;
if let hir::FnRetTy::Return(ty) = fn_decl.output { if let hir::FnRetTy::Return(ty) = fn_decl.output {
let mut v = StaticLifetimeVisitor(vec![], tcx.hir()); let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
v.visit_ty(ty); v.visit_ty(ty);
if !v.0.is_empty() { if !v.0.is_empty() {
span = v.0.clone().into(); span = v.0.clone().into();
for sp in v.0 { spans = v.0;
span.push_span_label(sp, "`'static` requirement introduced here");
}
add_label = false; add_label = false;
} }
} }
if add_label { let fn_decl_span = fn_decl.output.span();
span.push_span_label(
fn_decl.output.span(), subdiag = Some(ReqIntroducedLocations {
"requirement introduced by this return type",
);
}
span.push_span_label(cause.span, "because of this returned expression");
err.span_note(
span, span,
"`'static` lifetime requirement introduced by the return type", spans,
); fn_decl_span,
cause_span: cause.span,
add_label,
});
} }
} }
} }
let diag = ButNeedsToSatisfy {
sp,
influencer_point,
spans: spans.clone(),
// If any of the "captured here" labels appears on the same line or after
// `require_span`, we put it on a note to ensure the text flows by appearing
// always at the end.
require_span_as_note: require_as_note.then_some(require_span),
// We don't need a note, it's already at the end, it can be shown as a `span_label`.
require_span_as_label: (!require_as_note).then_some(require_span),
req_introduces_loc: subdiag,
has_lifetime: sup_r.has_name(),
lifetime: sup_r.to_string(),
spans_empty,
bound,
};
let mut err = self.tcx().sess.create_err(diag);
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
let mut override_error_code = None; let mut override_error_code = None;
@ -251,12 +227,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} }
if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
// Provide a more targeted error code and description. // Provide a more targeted error code and description.
err.code(rustc_errors::error_code!(E0772)); let retarget_subdiag = MoreTargeted { ident };
err.set_primary_message(&format!( retarget_subdiag.add_to_diagnostic(&mut err);
"{} has {} but calling `{}` introduces an implicit `'static` lifetime \
requirement",
param_name, lifetime, ident,
));
} }
let arg = match param.param.pat.simple_ident() { let arg = match param.param.pat.simple_ident() {
@ -551,21 +523,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let mut traits = vec![]; let mut traits = vec![];
let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did); let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
hir_v.visit_ty(&self_ty); hir_v.visit_ty(&self_ty);
for span in &traits { for &span in &traits {
let mut multi_span: MultiSpan = vec![*span].into(); let subdiag = DynTraitConstraintSuggestion { span, ident };
multi_span subdiag.add_to_diagnostic(err);
.push_span_label(*span, "this has an implicit `'static` lifetime requirement");
multi_span.push_span_label(
ident.span,
"calling this method introduces the `impl`'s 'static` requirement",
);
err.span_note(multi_span, "the used `impl` has a `'static` requirement");
err.span_suggestion_verbose(
span.shrink_to_hi(),
"consider relaxing the implicit `'static` requirement",
" + '_",
Applicability::MaybeIncorrect,
);
suggested = true; suggested = true;
} }
} }

View file

@ -1,10 +1,11 @@
//! Error Reporting for `impl` items that do not match the obligations from their `trait`. //! Error Reporting for `impl` items that do not match the obligations from their `trait`.
use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::Subtype; use crate::infer::Subtype;
use crate::traits::ObligationCauseCode::CompareImplItemObligation; use crate::traits::ObligationCauseCode::CompareImplItemObligation;
use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -51,10 +52,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
trait_def_id: DefId, trait_def_id: DefId,
) -> ErrorGuaranteed { ) -> ErrorGuaranteed {
let trait_sp = self.tcx().def_span(trait_def_id); let trait_sp = self.tcx().def_span(trait_def_id);
let mut err = self
.tcx()
.sess
.struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
// Mark all unnamed regions in the type with a number. // Mark all unnamed regions in the type with a number.
// This diagnostic is called in response to lifetime errors, so be informative. // This diagnostic is called in response to lifetime errors, so be informative.
@ -91,9 +88,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let found = let found =
self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
err.span_label(sp, &format!("found `{}`", found));
err.span_label(trait_sp, &format!("expected `{}`", expected));
// Get the span of all the used type parameters in the method. // Get the span of all the used type parameters in the method.
let assoc_item = self.tcx().associated_item(trait_def_id); let assoc_item = self.tcx().associated_item(trait_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
@ -110,26 +104,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} }
_ => {} _ => {}
} }
let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
for &span in &visitor.types {
type_param_span
.push_span_label(span, "consider borrowing this type parameter in the trait");
}
err.note(&format!("expected `{}`\n found `{}`", expected, found)); let diag = TraitImplDiff {
sp,
trait_sp,
note: (),
param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
expected,
found,
};
err.span_help( self.tcx().sess.emit_err(diag)
type_param_span,
"the lifetime requirements from the `impl` do not correspond to the requirements in \
the `trait`",
);
if visitor.types.is_empty() {
err.help(
"verify the lifetime relationships in the `trait` and `impl` between the `self` \
argument, the other inputs and its output",
);
}
err.emit()
} }
} }

View file

@ -1515,7 +1515,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
count: 1, count: 1,
}; };
let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime); let elision_candidate = LifetimeElisionCandidate::Missing(missing_lifetime);
for rib in self.lifetime_ribs.iter().rev() { for (i, rib) in self.lifetime_ribs.iter().enumerate().rev() {
debug!(?rib.kind); debug!(?rib.kind);
match rib.kind { match rib.kind {
LifetimeRibKind::AnonymousCreateParameter { binder, .. } => { LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
@ -1532,16 +1532,31 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
} else { } else {
("`'_` cannot be used here", "`'_` is a reserved lifetime name") ("`'_` cannot be used here", "`'_` is a reserved lifetime name")
}; };
rustc_errors::struct_span_err!( let mut diag = rustc_errors::struct_span_err!(
self.r.session, self.r.session,
lifetime.ident.span, lifetime.ident.span,
E0637, E0637,
"{}", "{}",
msg, msg,
) );
.span_label(lifetime.ident.span, note) diag.span_label(lifetime.ident.span, note);
.emit(); if elided {
for rib in self.lifetime_ribs[i..].iter().rev() {
if let LifetimeRibKind::Generics {
span,
kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound,
..
} = &rib.kind
{
diag.span_help(
*span,
"consider introducing a higher-ranked lifetime here with `for<'a>`",
);
break;
}
}
}
diag.emit();
self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate);
return; return;
} }

View file

@ -2821,9 +2821,9 @@ impl<T, A: Allocator> From<Vec<T, A>> for VecDeque<T, A> {
/// [`Vec<T>`]: crate::vec::Vec /// [`Vec<T>`]: crate::vec::Vec
/// [`VecDeque<T>`]: crate::collections::VecDeque /// [`VecDeque<T>`]: crate::collections::VecDeque
/// ///
/// In its current implementation, this is a very cheap /// This conversion is guaranteed to run in *O*(1) time
/// conversion. This isn't yet a guarantee though, and /// and to not re-allocate the `Vec`'s buffer or allocate
/// shouldn't be relied on. /// any additional memory.
#[inline] #[inline]
fn from(other: Vec<T, A>) -> Self { fn from(other: Vec<T, A>) -> Self {
let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc(); let (ptr, len, cap, alloc) = other.into_raw_parts_with_alloc();

View file

@ -126,7 +126,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
// zero so it won't be dropped later, and thus it's okay to take it here. // zero so it won't be dropped later, and thus it's okay to take it here.
unsafe { ManuallyDrop::take(&mut self.element) } unsafe { ManuallyDrop::take(&mut self.element) }
} else { } else {
A::clone(&mut self.element) A::clone(&self.element)
}) })
} }

View file

@ -623,6 +623,12 @@ impl<T: ?Sized> !Sync for *mut T {}
/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so /// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so
/// as not to indicate ownership. /// as not to indicate ownership.
/// ///
/// ## Layout
///
/// For all `T`, the following are guaranteed:
/// * `size_of::<PhantomData<T>>() == 0`
/// * `align_of::<PhantomData<T>>() == 1`
///
/// [drop check]: ../../nomicon/dropck.html /// [drop check]: ../../nomicon/dropck.html
#[lang = "phantom_data"] #[lang = "phantom_data"]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]

View file

@ -317,7 +317,7 @@ impl<T, S> HashSet<T, S> {
/// ///
/// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]); /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
/// set.retain(|&k| k % 2 == 0); /// set.retain(|&k| k % 2 == 0);
/// assert_eq!(set.len(), 3); /// assert_eq!(set, HashSet::from([2, 4, 6]));
/// ``` /// ```
/// ///
/// # Performance /// # Performance

View file

@ -1651,10 +1651,6 @@ in storage.js
margin-top: 1em; margin-top: 1em;
} }
.content {
margin-left: 0px;
}
.anchor { .anchor {
display: none !important; display: none !important;
} }

View file

@ -8,10 +8,9 @@ struct Point {
fn main() { fn main() {
let mut c = { let mut c = {
let mut p = Point {x: "1".to_string(), y: "2".to_string() }; let mut p = Point {x: "1".to_string(), y: "2".to_string() };
|| { || { //~ ERROR closure may outlive the current block, but it borrows `p`
let x = &mut p.x; let x = &mut p.x;
println!("{:?}", p); println!("{:?}", p);
//~^ ERROR `p` does not live long enough
} }
}; };
c(); c();

View file

@ -1,18 +1,22 @@
error[E0597]: `p` does not live long enough error[E0373]: closure may outlive the current block, but it borrows `p`, which is owned by the current block
--> $DIR/borrowck-3.rs:13:29 --> $DIR/borrowck-3.rs:11:9
| |
LL | let mut c = {
| ----- borrow later stored here
LL | let mut p = Point {x: "1".to_string(), y: "2".to_string() };
LL | || { LL | || {
| -- value captured here | ^^ may outlive borrowed value `p`
LL | let x = &mut p.x; LL | let x = &mut p.x;
LL | println!("{:?}", p); LL | println!("{:?}", p);
| ^ borrowed value does not live long enough | - `p` is borrowed here
... |
LL | }; note: block requires argument type to outlive `'1`
| - `p` dropped here while still borrowed --> $DIR/borrowck-3.rs:9:9
|
LL | let mut c = {
| ^^^^^
help: to force the closure to take ownership of `p` (and any other referenced variables), use the `move` keyword
|
LL | move || {
| ++++
error: aborting due to previous error error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`. For more information about this error, try `rustc --explain E0373`.

View file

@ -21,6 +21,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
| |
LL | T: Into<&u32>, LL | T: Into<&u32>,
| ^ explicit lifetime name needed here | ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/E0637.rs:13:8
|
LL | T: Into<&u32>,
| ^
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View file

@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
| |
LL | fn should_error<T>() where T : Into<&u32> {} LL | fn should_error<T>() where T : Into<&u32> {}
| ^ explicit lifetime name needed here | ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:5:32
|
LL | fn should_error<T>() where T : Into<&u32> {}
| ^
error[E0106]: missing lifetime specifier error[E0106]: missing lifetime specifier
--> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20 --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:20

View file

@ -84,42 +84,47 @@ fn expect_aborted(status: ExitStatus) {
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
{ {
// Android signals an abort() call with SIGSEGV at address 0xdeadbaad assert!(signal == libc::SIGABRT || signal == libc::SIGSEGV);
// See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
assert!(signal == libc::SIGSEGV);
// Additional checks performed: if signal == libc::SIGSEGV {
// 1. Find last tombstone (similar to coredump but in text format) from the // Pre-KitKat versions of Android signal an abort() with SIGSEGV at address 0xdeadbaad
// same executable (path) as we are (must be because of usage of fork): // See e.g. https://groups.google.com/g/android-ndk/c/laW1CJc7Icc
// This ensures that we look into the correct tombstone. //
// 2. Cause of crash is a SIGSEGV with address 0xdeadbaad. // This behavior was changed in KitKat to send a standard SIGABRT signal.
// 3. libc::abort call is in one of top two functions on callstack. // See: https://r.android.com/60341
// The last two steps distinguish between a normal SIGSEGV and one caused //
// by libc::abort. // Additional checks performed:
// 1. Find last tombstone (similar to coredump but in text format) from the
// same executable (path) as we are (must be because of usage of fork):
// This ensures that we look into the correct tombstone.
// 2. Cause of crash is a SIGSEGV with address 0xdeadbaad.
// 3. libc::abort call is in one of top two functions on callstack.
// The last two steps distinguish between a normal SIGSEGV and one caused
// by libc::abort.
let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap(); let this_exe = std::env::current_exe().unwrap().into_os_string().into_string().unwrap();
let exe_string = format!(">>> {this_exe} <<<"); let exe_string = format!(">>> {this_exe} <<<");
let tombstone = (0..100) let tombstone = (0..100)
.map(|n| format!("/data/tombstones/tombstone_{n:02}")) .map(|n| format!("/data/tombstones/tombstone_{n:02}"))
.filter(|f| std::path::Path::new(&f).exists()) .filter(|f| std::path::Path::new(&f).exists())
.map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file")) .map(|f| std::fs::read_to_string(&f).expect("Cannot read tombstone file"))
.filter(|f| f.contains(&exe_string)) .filter(|f| f.contains(&exe_string))
.last() .last()
.expect("no tombstone found"); .expect("no tombstone found");
println!("Content of tombstone:\n{tombstone}"); println!("Content of tombstone:\n{tombstone}");
assert!( assert!(tombstone
tombstone.contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad") .contains("signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad"));
); let abort_on_top = tombstone
let abort_on_top = tombstone .lines()
.lines() .skip_while(|l| !l.contains("backtrace:"))
.skip_while(|l| !l.contains("backtrace:")) .skip(1)
.skip(1) .take_while(|l| l.starts_with(" #"))
.take_while(|l| l.starts_with(" #")) .take(2)
.take(2) .any(|f| f.contains("/system/lib/libc.so (abort"));
.any(|f| f.contains("/system/lib/libc.so (abort")); assert!(abort_on_top);
assert!(abort_on_top); }
} }
} }

View file

@ -5,7 +5,7 @@
fn main() { fn main() {
let _f = { let _f = {
let x = 0; let x = 0;
|| x //~ ERROR `x` does not live long enough || x //~ ERROR closure may outlive the current block, but it borrows `x`
}; };
_f; _f;
} }

View file

@ -1,16 +1,21 @@
error[E0597]: `x` does not live long enough error[E0373]: closure may outlive the current block, but it borrows `x`, which is owned by the current block
--> $DIR/unboxed-closure-region.rs:8:12 --> $DIR/unboxed-closure-region.rs:8:9
|
LL | || x
| ^^ - `x` is borrowed here
| |
| may outlive borrowed value `x`
|
note: block requires argument type to outlive `'1`
--> $DIR/unboxed-closure-region.rs:6:9
| |
LL | let _f = { LL | let _f = {
| -- borrow later stored here | ^^
LL | let x = 0; help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
LL | || x |
| -- ^ borrowed value does not live long enough LL | move || x
| | | ++++
| value captured here
LL | };
| - `x` dropped here while still borrowed
error: aborting due to previous error error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`. For more information about this error, try `rustc --explain E0373`.

View file

@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
| |
LL | T: WithType<&u32> LL | T: WithType<&u32>
| ^ explicit lifetime name needed here | ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
|
LL | T: WithType<&u32>
| ^
error: aborting due to previous error error: aborting due to previous error

View file

@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
| |
LL | T: WithType<&u32> LL | T: WithType<&u32>
| ^ explicit lifetime name needed here | ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-inherent-impl-ampersand.rs:13:8
|
LL | T: WithType<&u32>
| ^
error: aborting due to previous error error: aborting due to previous error

View file

@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
| |
LL | T: WithType<&u32> LL | T: WithType<&u32>
| ^ explicit lifetime name needed here | ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-trait-impl-region.rs:11:8
|
LL | T: WithType<&u32>
| ^
error: aborting due to previous error error: aborting due to previous error

View file

@ -3,6 +3,12 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
| |
LL | T: WithType<&u32> LL | T: WithType<&u32>
| ^ explicit lifetime name needed here | ^ explicit lifetime name needed here
|
help: consider introducing a higher-ranked lifetime here with `for<'a>`
--> $DIR/where-clause-trait-impl-region.rs:11:8
|
LL | T: WithType<&u32>
| ^
error: aborting due to previous error error: aborting due to previous error

View file

@ -20,6 +20,7 @@ fn bindings() {
category, category,
span, span,
&format!("`{}`", name), &format!("`{}`", name),
"function",
), ),
( (
ref name, ref name,