Auto merge of #117444 - matthiaskrgr:rollup-43s0spc, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #116267 (Some codegen cleanups around SIMD checks) - #116712 (When encountering unclosed delimiters during lexing, check for diff markers) - #117416 (Also consider TAIT to be uncomputable if the MIR body is tainted) - #117421 (coverage: Replace impossible `coverage::Error` with assertions) - #117438 (Do not ICE on constant evaluation failure in GVN.) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
045f158d7b
@ -935,9 +935,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
|
||||
macro_rules! require_simd {
|
||||
($ty: expr, $diag: expr) => {
|
||||
require!($ty.is_simd(), $diag)
|
||||
};
|
||||
($ty: expr, $variant:ident) => {{
|
||||
require!($ty.is_simd(), InvalidMonomorphization::$variant { span, name, ty: $ty });
|
||||
$ty.simd_size_and_type(bx.tcx())
|
||||
}};
|
||||
}
|
||||
|
||||
let tcx = bx.tcx();
|
||||
@ -946,12 +947,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
let arg_tys = sig.inputs();
|
||||
|
||||
if name == sym::simd_select_bitmask {
|
||||
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, _) = require_simd!(arg_tys[1], SimdArgument);
|
||||
|
||||
let expected_int_bits = (len.max(8) - 1).next_power_of_two();
|
||||
let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
|
||||
@ -988,7 +984,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
|
||||
// every intrinsic below takes a SIMD vector as its first argument
|
||||
require_simd!(arg_tys[0], InvalidMonomorphization::SimdInput { span, name, ty: arg_tys[0] });
|
||||
let (in_len, in_elem) = require_simd!(arg_tys[0], SimdInput);
|
||||
let in_ty = arg_tys[0];
|
||||
|
||||
let comparison = match name {
|
||||
@ -1001,11 +997,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
|
||||
if let Some(cmp_op) = comparison {
|
||||
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) = require_simd!(ret_ty, SimdReturn);
|
||||
|
||||
require!(
|
||||
in_len == out_len,
|
||||
@ -1041,8 +1034,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
.unwrap_branch();
|
||||
let n = idx.len() as u64;
|
||||
|
||||
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) = require_simd!(ret_ty, SimdReturn);
|
||||
require!(
|
||||
out_len == n,
|
||||
InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
|
||||
@ -1099,8 +1091,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}),
|
||||
};
|
||||
|
||||
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) = require_simd!(ret_ty, SimdReturn);
|
||||
require!(
|
||||
out_len == n,
|
||||
InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
|
||||
@ -1179,11 +1170,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
if name == sym::simd_select {
|
||||
let m_elem_ty = in_elem;
|
||||
let m_len = in_len;
|
||||
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, _) = require_simd!(arg_tys[1], SimdArgument);
|
||||
require!(
|
||||
m_len == v_len,
|
||||
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
|
||||
@ -1401,20 +1388,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
// * M: any integer width is supported, will be truncated to i1
|
||||
|
||||
// All types must be simd vector types
|
||||
require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
|
||||
require_simd!(
|
||||
arg_tys[1],
|
||||
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 });
|
||||
|
||||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = require_simd!(in_ty, SimdFirst);
|
||||
let (out_len, element_ty1) = require_simd!(arg_tys[1], SimdSecond);
|
||||
// The element type of the third argument must be a signed integer type of any width:
|
||||
let (out_len2, element_ty2) = require_simd!(arg_tys[2], SimdThird);
|
||||
require_simd!(ret_ty, SimdReturn);
|
||||
|
||||
// Of the same length:
|
||||
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphization::SecondArgumentLength {
|
||||
@ -1444,11 +1427,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
|
||||
);
|
||||
|
||||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
|
||||
require!(
|
||||
matches!(
|
||||
element_ty1.kind(),
|
||||
@ -1465,20 +1443,15 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
);
|
||||
|
||||
// The element type of the third argument must be a signed integer type of any width:
|
||||
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
match element_ty2.kind() {
|
||||
ty::Int(_) => (),
|
||||
_ => {
|
||||
require!(
|
||||
false,
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
}
|
||||
);
|
||||
return_error!(InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1527,19 +1500,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
// * M: any integer width is supported, will be truncated to i1
|
||||
|
||||
// All types must be simd vector types
|
||||
require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
|
||||
require_simd!(
|
||||
arg_tys[1],
|
||||
InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
|
||||
);
|
||||
require_simd!(
|
||||
arg_tys[2],
|
||||
InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
|
||||
);
|
||||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = require_simd!(in_ty, SimdFirst);
|
||||
let (element_len1, element_ty1) = require_simd!(arg_tys[1], SimdSecond);
|
||||
let (element_len2, element_ty2) = require_simd!(arg_tys[2], SimdThird);
|
||||
|
||||
// Of the same length:
|
||||
let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
require!(
|
||||
in_len == element_len1,
|
||||
InvalidMonomorphization::SecondArgumentLength {
|
||||
@ -1563,12 +1530,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
);
|
||||
|
||||
// The second argument must be a simd vector with an element type that's a pointer
|
||||
// to the element type of the first argument
|
||||
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||
|
||||
require!(
|
||||
matches!(
|
||||
element_ty1.kind(),
|
||||
@ -1590,15 +1551,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
match element_ty2.kind() {
|
||||
ty::Int(_) => (),
|
||||
_ => {
|
||||
require!(
|
||||
false,
|
||||
InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
}
|
||||
);
|
||||
return_error!(InvalidMonomorphization::ThirdArgElementType {
|
||||
span,
|
||||
name,
|
||||
expected_element: element_ty2,
|
||||
third_arg: arg_tys[2]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1794,8 +1752,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
bitwise_red!(simd_reduce_any: vector_reduce_or, true);
|
||||
|
||||
if name == sym::simd_cast_ptr {
|
||||
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) = require_simd!(ret_ty, SimdReturn);
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphization::ReturnLengthInputType {
|
||||
@ -1843,8 +1800,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
|
||||
if name == sym::simd_expose_addr {
|
||||
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) = require_simd!(ret_ty, SimdReturn);
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphization::ReturnLengthInputType {
|
||||
@ -1872,8 +1828,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
|
||||
if name == sym::simd_from_exposed_addr {
|
||||
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) = require_simd!(ret_ty, SimdReturn);
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphization::ReturnLengthInputType {
|
||||
@ -1901,8 +1856,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
|
||||
if name == sym::simd_cast || name == sym::simd_as {
|
||||
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) = require_simd!(ret_ty, SimdReturn);
|
||||
require!(
|
||||
in_len == out_len,
|
||||
InvalidMonomorphization::ReturnLengthInputType {
|
||||
@ -1989,17 +1943,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
}
|
||||
_ => { /* Unsupported. Fallthrough. */ }
|
||||
}
|
||||
require!(
|
||||
false,
|
||||
InvalidMonomorphization::UnsupportedCast {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
in_elem,
|
||||
ret_ty,
|
||||
out_elem
|
||||
}
|
||||
);
|
||||
return_error!(InvalidMonomorphization::UnsupportedCast {
|
||||
span,
|
||||
name,
|
||||
in_ty,
|
||||
in_elem,
|
||||
ret_ty,
|
||||
out_elem
|
||||
});
|
||||
}
|
||||
macro_rules! arith_binary {
|
||||
($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
|
||||
@ -2010,8 +1961,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
})*
|
||||
_ => {},
|
||||
}
|
||||
require!(
|
||||
false,
|
||||
return_error!(
|
||||
InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
|
||||
);
|
||||
})*
|
||||
@ -2041,8 +1991,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
||||
})*
|
||||
_ => {},
|
||||
}
|
||||
require!(
|
||||
false,
|
||||
return_error!(
|
||||
InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
|
||||
);
|
||||
})*
|
||||
|
@ -183,9 +183,17 @@ impl TaitConstraintLocator<'_> {
|
||||
};
|
||||
|
||||
// Use borrowck to get the type with unerased regions.
|
||||
let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
|
||||
debug!(?concrete_opaque_types);
|
||||
if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
|
||||
let borrowck_results = &self.tcx.mir_borrowck(item_def_id);
|
||||
|
||||
// If the body was tainted, then assume the opaque may have been constrained and just set it to error.
|
||||
if let Some(guar) = borrowck_results.tainted_by_errors {
|
||||
self.found =
|
||||
Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: Ty::new_error(self.tcx, guar) });
|
||||
return;
|
||||
}
|
||||
|
||||
debug!(?borrowck_results.concrete_opaque_types);
|
||||
if let Some(&concrete_type) = borrowck_results.concrete_opaque_types.get(&self.def_id) {
|
||||
debug!(?concrete_type, "found constraint");
|
||||
if let Some(prev) = &mut self.found {
|
||||
if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
|
||||
|
@ -520,11 +520,13 @@ impl<'tcx> Const<'tcx> {
|
||||
// types are fine though.
|
||||
ty::ConstKind::Value(_) => c.ty().is_primitive(),
|
||||
ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false,
|
||||
// This can happen if evaluation of a constant failed. The result does not matter
|
||||
// much since compilation is doomed.
|
||||
ty::ConstKind::Error(..) => false,
|
||||
// Should not appear in runtime MIR.
|
||||
ty::ConstKind::Infer(..)
|
||||
| ty::ConstKind::Bound(..)
|
||||
| ty::ConstKind::Placeholder(..)
|
||||
| ty::ConstKind::Error(..) => bug!(),
|
||||
| ty::ConstKind::Placeholder(..) => bug!(),
|
||||
},
|
||||
Const::Unevaluated(..) => false,
|
||||
// If the same slice appears twice in the MIR, we cannot guarantee that we will
|
||||
|
@ -1,5 +1,3 @@
|
||||
use super::Error;
|
||||
|
||||
use super::graph;
|
||||
|
||||
use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops};
|
||||
@ -53,7 +51,7 @@ pub(super) struct CoverageCounters {
|
||||
/// edge between two BCBs.
|
||||
bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
|
||||
/// Tracks which BCBs have a counter associated with some incoming edge.
|
||||
/// Only used by debug assertions, to verify that BCBs with incoming edge
|
||||
/// Only used by assertions, to verify that BCBs with incoming edge
|
||||
/// counters do not have their own physical counters (expressions are allowed).
|
||||
bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>,
|
||||
/// Table of expression data, associating each expression ID with its
|
||||
@ -81,7 +79,7 @@ impl CoverageCounters {
|
||||
&mut self,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
|
||||
) -> Result<(), Error> {
|
||||
) {
|
||||
MakeBcbCounters::new(self, basic_coverage_blocks).make_bcb_counters(bcb_has_coverage_spans)
|
||||
}
|
||||
|
||||
@ -111,26 +109,23 @@ impl CoverageCounters {
|
||||
self.expressions.len()
|
||||
}
|
||||
|
||||
fn set_bcb_counter(
|
||||
&mut self,
|
||||
bcb: BasicCoverageBlock,
|
||||
counter_kind: BcbCounter,
|
||||
) -> Result<CovTerm, Error> {
|
||||
debug_assert!(
|
||||
fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> CovTerm {
|
||||
assert!(
|
||||
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
|
||||
// have an expression (to be injected into an existing `BasicBlock` represented by this
|
||||
// `BasicCoverageBlock`).
|
||||
counter_kind.is_expression() || !self.bcb_has_incoming_edge_counters.contains(bcb),
|
||||
"attempt to add a `Counter` to a BCB target with existing incoming edge counters"
|
||||
);
|
||||
|
||||
let term = counter_kind.as_term();
|
||||
if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) {
|
||||
Error::from_string(format!(
|
||||
bug!(
|
||||
"attempt to set a BasicCoverageBlock coverage counter more than once; \
|
||||
{bcb:?} already had counter {replaced:?}",
|
||||
))
|
||||
);
|
||||
} else {
|
||||
Ok(term)
|
||||
term
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,27 +134,26 @@ impl CoverageCounters {
|
||||
from_bcb: BasicCoverageBlock,
|
||||
to_bcb: BasicCoverageBlock,
|
||||
counter_kind: BcbCounter,
|
||||
) -> Result<CovTerm, Error> {
|
||||
if level_enabled!(tracing::Level::DEBUG) {
|
||||
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
|
||||
// have an expression (to be injected into an existing `BasicBlock` represented by this
|
||||
// `BasicCoverageBlock`).
|
||||
if self.bcb_counter(to_bcb).is_some_and(|c| !c.is_expression()) {
|
||||
return Error::from_string(format!(
|
||||
"attempt to add an incoming edge counter from {from_bcb:?} when the target BCB already \
|
||||
has a `Counter`"
|
||||
));
|
||||
}
|
||||
) -> CovTerm {
|
||||
// If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
|
||||
// have an expression (to be injected into an existing `BasicBlock` represented by this
|
||||
// `BasicCoverageBlock`).
|
||||
if let Some(node_counter) = self.bcb_counter(to_bcb) && !node_counter.is_expression() {
|
||||
bug!(
|
||||
"attempt to add an incoming edge counter from {from_bcb:?} \
|
||||
when the target BCB already has {node_counter:?}"
|
||||
);
|
||||
}
|
||||
|
||||
self.bcb_has_incoming_edge_counters.insert(to_bcb);
|
||||
let term = counter_kind.as_term();
|
||||
if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) {
|
||||
Error::from_string(format!(
|
||||
bug!(
|
||||
"attempt to set an edge counter more than once; from_bcb: \
|
||||
{from_bcb:?} already had counter {replaced:?}",
|
||||
))
|
||||
);
|
||||
} else {
|
||||
Ok(term)
|
||||
term
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,14 +207,7 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
/// One way to predict which branch executes the least is by considering loops. A loop is exited
|
||||
/// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost
|
||||
/// always executed less than the branch that does not exit the loop.
|
||||
///
|
||||
/// Returns any non-code-span expressions created to represent intermediate values (such as to
|
||||
/// add two counters so the result can be subtracted from another counter), or an Error with
|
||||
/// message for subsequent debugging.
|
||||
fn make_bcb_counters(
|
||||
&mut self,
|
||||
bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
|
||||
) -> Result<(), Error> {
|
||||
fn make_bcb_counters(&mut self, bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool) {
|
||||
debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
|
||||
|
||||
// Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated
|
||||
@ -237,10 +224,10 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
while let Some(bcb) = traversal.next() {
|
||||
if bcb_has_coverage_spans(bcb) {
|
||||
debug!("{:?} has at least one coverage span. Get or make its counter", bcb);
|
||||
let branching_counter_operand = self.get_or_make_counter_operand(bcb)?;
|
||||
let branching_counter_operand = self.get_or_make_counter_operand(bcb);
|
||||
|
||||
if self.bcb_needs_branch_counters(bcb) {
|
||||
self.make_branch_counters(&traversal, bcb, branching_counter_operand)?;
|
||||
self.make_branch_counters(&traversal, bcb, branching_counter_operand);
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
@ -251,14 +238,11 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
if traversal.is_complete() {
|
||||
Ok(())
|
||||
} else {
|
||||
Error::from_string(format!(
|
||||
"`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
|
||||
traversal.unvisited(),
|
||||
))
|
||||
}
|
||||
assert!(
|
||||
traversal.is_complete(),
|
||||
"`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
|
||||
traversal.unvisited(),
|
||||
);
|
||||
}
|
||||
|
||||
fn make_branch_counters(
|
||||
@ -266,7 +250,7 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
traversal: &TraverseCoverageGraphWithLoops<'_>,
|
||||
branching_bcb: BasicCoverageBlock,
|
||||
branching_counter_operand: CovTerm,
|
||||
) -> Result<(), Error> {
|
||||
) {
|
||||
let branches = self.bcb_branches(branching_bcb);
|
||||
debug!(
|
||||
"{:?} has some branch(es) without counters:\n {}",
|
||||
@ -299,10 +283,10 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
counter",
|
||||
branch, branching_bcb
|
||||
);
|
||||
self.get_or_make_counter_operand(branch.target_bcb)?
|
||||
self.get_or_make_counter_operand(branch.target_bcb)
|
||||
} else {
|
||||
debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch);
|
||||
self.get_or_make_edge_counter_operand(branching_bcb, branch.target_bcb)?
|
||||
self.get_or_make_edge_counter_operand(branching_bcb, branch.target_bcb)
|
||||
};
|
||||
if let Some(sumup_counter_operand) =
|
||||
some_sumup_counter_operand.replace(branch_counter_operand)
|
||||
@ -337,19 +321,18 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
debug!("{:?} gets an expression: {:?}", expression_branch, expression);
|
||||
let bcb = expression_branch.target_bcb;
|
||||
if expression_branch.is_only_path_to_target() {
|
||||
self.coverage_counters.set_bcb_counter(bcb, expression)?;
|
||||
self.coverage_counters.set_bcb_counter(bcb, expression);
|
||||
} else {
|
||||
self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression)?;
|
||||
self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> Result<CovTerm, Error> {
|
||||
fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> CovTerm {
|
||||
// If the BCB already has a counter, return it.
|
||||
if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] {
|
||||
debug!("{bcb:?} already has a counter: {counter_kind:?}");
|
||||
return Ok(counter_kind.as_term());
|
||||
return counter_kind.as_term();
|
||||
}
|
||||
|
||||
// A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
|
||||
@ -378,10 +361,10 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
|
||||
let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter();
|
||||
let first_edge_counter_operand =
|
||||
self.get_or_make_edge_counter_operand(predecessors.next().unwrap(), bcb)?;
|
||||
self.get_or_make_edge_counter_operand(predecessors.next().unwrap(), bcb);
|
||||
let mut some_sumup_edge_counter_operand = None;
|
||||
for predecessor in predecessors {
|
||||
let edge_counter_operand = self.get_or_make_edge_counter_operand(predecessor, bcb)?;
|
||||
let edge_counter_operand = self.get_or_make_edge_counter_operand(predecessor, bcb);
|
||||
if let Some(sumup_edge_counter_operand) =
|
||||
some_sumup_edge_counter_operand.replace(edge_counter_operand)
|
||||
{
|
||||
@ -411,7 +394,7 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
&mut self,
|
||||
from_bcb: BasicCoverageBlock,
|
||||
to_bcb: BasicCoverageBlock,
|
||||
) -> Result<CovTerm, Error> {
|
||||
) -> CovTerm {
|
||||
// If the source BCB has only one successor (assumed to be the given target), an edge
|
||||
// counter is unnecessary. Just get or make a counter for the source BCB.
|
||||
let successors = self.bcb_successors(from_bcb).iter();
|
||||
@ -424,7 +407,7 @@ impl<'a> MakeBcbCounters<'a> {
|
||||
self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb))
|
||||
{
|
||||
debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}");
|
||||
return Ok(counter_kind.as_term());
|
||||
return counter_kind.as_term();
|
||||
}
|
||||
|
||||
// Make a new counter to count this edge.
|
||||
|
@ -26,18 +26,6 @@ use rustc_span::def_id::DefId;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{ExpnKind, SourceFile, Span, Symbol};
|
||||
|
||||
/// A simple error message wrapper for `coverage::Error`s.
|
||||
#[derive(Debug)]
|
||||
struct Error {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn from_string<T>(message: String) -> Result<T, Error> {
|
||||
Err(Self { message })
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
|
||||
/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
|
||||
/// to construct the coverage map.
|
||||
@ -167,10 +155,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
|
||||
// `BasicCoverageBlock`s not already associated with a coverage span.
|
||||
let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
|
||||
self.coverage_counters
|
||||
.make_bcb_counters(&mut self.basic_coverage_blocks, bcb_has_coverage_spans)
|
||||
.unwrap_or_else(|e| {
|
||||
bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message)
|
||||
});
|
||||
.make_bcb_counters(&self.basic_coverage_blocks, bcb_has_coverage_spans);
|
||||
|
||||
let mappings = self.create_mappings_and_inject_coverage_statements(&coverage_spans);
|
||||
|
||||
|
@ -647,15 +647,13 @@ fn test_traverse_coverage_with_loops() {
|
||||
fn test_make_bcb_counters() {
|
||||
rustc_span::create_default_session_globals_then(|| {
|
||||
let mir_body = goto_switchint();
|
||||
let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
||||
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
||||
// Historically this test would use `spans` internals to set up fake
|
||||
// coverage spans for BCBs 1 and 2. Now we skip that step and just tell
|
||||
// BCB counter construction that those BCBs have spans.
|
||||
let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize());
|
||||
let mut coverage_counters = counters::CoverageCounters::new(&basic_coverage_blocks);
|
||||
coverage_counters
|
||||
.make_bcb_counters(&mut basic_coverage_blocks, bcb_has_coverage_spans)
|
||||
.expect("should be Ok");
|
||||
coverage_counters.make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
|
||||
assert_eq!(coverage_counters.num_expressions(), 0);
|
||||
|
||||
let_bcb!(1);
|
||||
|
@ -64,10 +64,10 @@ pub(crate) fn parse_token_trees<'a>(
|
||||
override_span,
|
||||
nbsp_is_whitespace: false,
|
||||
};
|
||||
let (token_trees, unmatched_delims) =
|
||||
let (stream, res, unmatched_delims) =
|
||||
tokentrees::TokenTreesReader::parse_all_token_trees(string_reader);
|
||||
match token_trees {
|
||||
Ok(stream) if unmatched_delims.is_empty() => Ok(stream),
|
||||
match res {
|
||||
Ok(()) if unmatched_delims.is_empty() => Ok(stream),
|
||||
_ => {
|
||||
// Return error if there are unmatched delimiters or unclosed delimiters.
|
||||
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
|
||||
@ -79,9 +79,11 @@ pub(crate) fn parse_token_trees<'a>(
|
||||
err.buffer(&mut buffer);
|
||||
}
|
||||
}
|
||||
if let Err(err) = token_trees {
|
||||
// Add unclosing delimiter error
|
||||
err.buffer(&mut buffer);
|
||||
if let Err(errs) = res {
|
||||
// Add unclosing delimiter or diff marker errors
|
||||
for err in errs {
|
||||
err.buffer(&mut buffer);
|
||||
}
|
||||
}
|
||||
Err(buffer)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use super::{StringReader, UnmatchedDelim};
|
||||
use rustc_ast::token::{self, Delimiter, Token};
|
||||
use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast_pretty::pprust::token_to_string;
|
||||
use rustc_errors::{PErr, PResult};
|
||||
use rustc_errors::PErr;
|
||||
|
||||
pub(super) struct TokenTreesReader<'a> {
|
||||
string_reader: StringReader<'a>,
|
||||
@ -18,36 +18,42 @@ pub(super) struct TokenTreesReader<'a> {
|
||||
impl<'a> TokenTreesReader<'a> {
|
||||
pub(super) fn parse_all_token_trees(
|
||||
string_reader: StringReader<'a>,
|
||||
) -> (PResult<'a, TokenStream>, Vec<UnmatchedDelim>) {
|
||||
) -> (TokenStream, Result<(), Vec<PErr<'a>>>, Vec<UnmatchedDelim>) {
|
||||
let mut tt_reader = TokenTreesReader {
|
||||
string_reader,
|
||||
token: Token::dummy(),
|
||||
diag_info: TokenTreeDiagInfo::default(),
|
||||
};
|
||||
let res = tt_reader.parse_token_trees(/* is_delimited */ false);
|
||||
(res, tt_reader.diag_info.unmatched_delims)
|
||||
let (stream, res) = tt_reader.parse_token_trees(/* is_delimited */ false);
|
||||
(stream, res, tt_reader.diag_info.unmatched_delims)
|
||||
}
|
||||
|
||||
// Parse a stream of tokens into a list of `TokenTree`s.
|
||||
fn parse_token_trees(&mut self, is_delimited: bool) -> PResult<'a, TokenStream> {
|
||||
fn parse_token_trees(
|
||||
&mut self,
|
||||
is_delimited: bool,
|
||||
) -> (TokenStream, Result<(), Vec<PErr<'a>>>) {
|
||||
self.token = self.string_reader.next_token().0;
|
||||
let mut buf = Vec::new();
|
||||
loop {
|
||||
match self.token.kind {
|
||||
token::OpenDelim(delim) => buf.push(self.parse_token_tree_open_delim(delim)?),
|
||||
token::OpenDelim(delim) => {
|
||||
buf.push(match self.parse_token_tree_open_delim(delim) {
|
||||
Ok(val) => val,
|
||||
Err(errs) => return (TokenStream::new(buf), Err(errs)),
|
||||
})
|
||||
}
|
||||
token::CloseDelim(delim) => {
|
||||
return if is_delimited {
|
||||
Ok(TokenStream::new(buf))
|
||||
} else {
|
||||
Err(self.close_delim_err(delim))
|
||||
};
|
||||
return (
|
||||
TokenStream::new(buf),
|
||||
if is_delimited { Ok(()) } else { Err(vec![self.close_delim_err(delim)]) },
|
||||
);
|
||||
}
|
||||
token::Eof => {
|
||||
return if is_delimited {
|
||||
Err(self.eof_err())
|
||||
} else {
|
||||
Ok(TokenStream::new(buf))
|
||||
};
|
||||
return (
|
||||
TokenStream::new(buf),
|
||||
if is_delimited { Err(vec![self.eof_err()]) } else { Ok(()) },
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
// Get the next normal token. This might require getting multiple adjacent
|
||||
@ -97,7 +103,10 @@ impl<'a> TokenTreesReader<'a> {
|
||||
err
|
||||
}
|
||||
|
||||
fn parse_token_tree_open_delim(&mut self, open_delim: Delimiter) -> PResult<'a, TokenTree> {
|
||||
fn parse_token_tree_open_delim(
|
||||
&mut self,
|
||||
open_delim: Delimiter,
|
||||
) -> Result<TokenTree, Vec<PErr<'a>>> {
|
||||
// The span for beginning of the delimited section
|
||||
let pre_span = self.token.span;
|
||||
|
||||
@ -106,7 +115,26 @@ impl<'a> TokenTreesReader<'a> {
|
||||
// Parse the token trees within the delimiters.
|
||||
// We stop at any delimiter so we can try to recover if the user
|
||||
// uses an incorrect delimiter.
|
||||
let tts = self.parse_token_trees(/* is_delimited */ true)?;
|
||||
let (tts, res) = self.parse_token_trees(/* is_delimited */ true);
|
||||
if let Err(mut errs) = res {
|
||||
// If there are unclosed delims, see if there are diff markers and if so, point them
|
||||
// out instead of complaining about the unclosed delims.
|
||||
let mut parser = crate::stream_to_parser(self.string_reader.sess, tts, None);
|
||||
let mut diff_errs = vec![];
|
||||
while parser.token != token::Eof {
|
||||
if let Err(diff_err) = parser.err_diff_marker() {
|
||||
diff_errs.push(diff_err);
|
||||
}
|
||||
parser.bump();
|
||||
}
|
||||
if !diff_errs.is_empty() {
|
||||
errs.iter_mut().for_each(|err| {
|
||||
err.delay_as_bug();
|
||||
});
|
||||
return Err(diff_errs);
|
||||
}
|
||||
return Err(errs);
|
||||
}
|
||||
|
||||
// Expand to cover the entire delimited token tree
|
||||
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
|
||||
|
@ -2808,8 +2808,15 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
pub fn recover_diff_marker(&mut self) {
|
||||
if let Err(mut err) = self.err_diff_marker() {
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn err_diff_marker(&mut self) -> PResult<'a, ()> {
|
||||
let Some(start) = self.diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else {
|
||||
return;
|
||||
return Ok(());
|
||||
};
|
||||
let mut spans = Vec::with_capacity(3);
|
||||
spans.push(start);
|
||||
@ -2856,8 +2863,7 @@ impl<'a> Parser<'a> {
|
||||
"for an explanation on these markers from the `git` documentation, visit \
|
||||
<https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
|
||||
);
|
||||
err.emit();
|
||||
FatalError.raise()
|
||||
Err(err)
|
||||
}
|
||||
|
||||
/// Parse and throw away a parenthesized comma separated
|
||||
|
21
tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
Normal file
21
tests/ui/consts/const-eval/issue-50814-2.mir-opt.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error[E0080]: evaluation of `<A<()> as Foo<()>>::BAR` failed
|
||||
--> $DIR/issue-50814-2.rs:16:24
|
||||
|
|
||||
LL | const BAR: usize = [5, 6, 7][T::BOO];
|
||||
| ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/issue-50814-2.rs:20:6
|
||||
|
|
||||
LL | &<A<T> as Foo<T>>::BAR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/issue-50814-2.rs:20:5
|
||||
|
|
||||
LL | &<A<T> as Foo<T>>::BAR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -1,17 +1,17 @@
|
||||
error[E0080]: evaluation of `<A<()> as Foo<()>>::BAR` failed
|
||||
--> $DIR/issue-50814-2.rs:14:24
|
||||
--> $DIR/issue-50814-2.rs:16:24
|
||||
|
|
||||
LL | const BAR: usize = [5, 6, 7][T::BOO];
|
||||
| ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 42
|
||||
|
||||
note: erroneous constant encountered
|
||||
--> $DIR/issue-50814-2.rs:18:6
|
||||
--> $DIR/issue-50814-2.rs:20:6
|
||||
|
|
||||
LL | &<A<T> as Foo<T>>::BAR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: the above error was encountered while instantiating `fn foo::<()>`
|
||||
--> $DIR/issue-50814-2.rs:30:22
|
||||
--> $DIR/issue-50814-2.rs:32:22
|
||||
|
|
||||
LL | println!("{:x}", foo::<()>() as *const usize as usize);
|
||||
| ^^^^^^^^^^^
|
@ -1,4 +1,6 @@
|
||||
// build-fail
|
||||
// revisions: normal mir-opt
|
||||
// [mir-opt]compile-flags: -Zmir-opt-level=4
|
||||
|
||||
trait C {
|
||||
const BOO: usize;
|
||||
|
9
tests/ui/parser/diff-markers/unclosed-delims-in-macro.rs
Normal file
9
tests/ui/parser/diff-markers/unclosed-delims-in-macro.rs
Normal file
@ -0,0 +1,9 @@
|
||||
macro_rules! foo {
|
||||
<<<<<<< HEAD
|
||||
//~^ ERROR encountered diff marker
|
||||
() {
|
||||
=======
|
||||
() { //
|
||||
>>>>>>> 7a4f13c blah blah blah
|
||||
}
|
||||
}
|
18
tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr
Normal file
18
tests/ui/parser/diff-markers/unclosed-delims-in-macro.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error: encountered diff marker
|
||||
--> $DIR/unclosed-delims-in-macro.rs:2:1
|
||||
|
|
||||
LL | <<<<<<< HEAD
|
||||
| ^^^^^^^ after this is the code before the merge
|
||||
...
|
||||
LL | =======
|
||||
| -------
|
||||
LL | () { //
|
||||
LL | >>>>>>> 7a4f13c blah blah blah
|
||||
| ^^^^^^^ above this are the incoming code changes
|
||||
|
|
||||
= help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
|
||||
= help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
|
||||
= note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
|
||||
|
||||
error: aborting due to previous error
|
||||
|
14
tests/ui/parser/diff-markers/unclosed-delims.rs
Normal file
14
tests/ui/parser/diff-markers/unclosed-delims.rs
Normal file
@ -0,0 +1,14 @@
|
||||
mod tests {
|
||||
#[test]
|
||||
<<<<<<< HEAD
|
||||
//~^ ERROR encountered diff marker
|
||||
//~| NOTE after this is the code before the merge
|
||||
//~| NOTE for an explanation on these markers
|
||||
fn test1() {
|
||||
=======
|
||||
//~^ NOTE
|
||||
fn test2() {
|
||||
>>>>>>> 7a4f13c blah blah blah
|
||||
//~^ NOTE above this are the incoming code changes
|
||||
}
|
||||
}
|
18
tests/ui/parser/diff-markers/unclosed-delims.stderr
Normal file
18
tests/ui/parser/diff-markers/unclosed-delims.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error: encountered diff marker
|
||||
--> $DIR/unclosed-delims.rs:3:1
|
||||
|
|
||||
LL | <<<<<<< HEAD
|
||||
| ^^^^^^^ after this is the code before the merge
|
||||
...
|
||||
LL | =======
|
||||
| -------
|
||||
...
|
||||
LL | >>>>>>> 7a4f13c blah blah blah
|
||||
| ^^^^^^^ above this are the incoming code changes
|
||||
|
|
||||
= help: if you're having merge conflicts after pulling new code, the top section is the code you already had and the bottom section is the remote code
|
||||
= help: if you're in the middle of a rebase, the top section is the code being rebased onto and the bottom section is the code coming from the current commit being rebased
|
||||
= note: for an explanation on these markers from the `git` documentation, visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,14 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
type Tait = impl Copy;
|
||||
// Make sure that this TAIT isn't considered unconstrained...
|
||||
|
||||
fn empty_opaque() -> Tait {
|
||||
if false {
|
||||
match empty_opaque() {}
|
||||
//~^ ERROR non-empty
|
||||
}
|
||||
0u8
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,17 @@
|
||||
error[E0004]: non-exhaustive patterns: type `Tait` is non-empty
|
||||
--> $DIR/unconstrained-due-to-bad-pattern.rs:8:15
|
||||
|
|
||||
LL | match empty_opaque() {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the matched value is of type `Tait`
|
||||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||
|
|
||||
LL ~ match empty_opaque() {
|
||||
LL + _ => todo!(),
|
||||
LL + }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0004`.
|
Loading…
x
Reference in New Issue
Block a user