Auto merge of #118395 - compiler-errors:rollup-c8yqlmw, r=compiler-errors
Rollup of 9 pull requests Successful merges: - #111133 (Detect Python-like slicing and suggest how to fix) - #114708 (Allow setting `rla` labels via `rustbot`) - #117526 (Account for `!` arm in tail `match` expr) - #118172 (Add `pretty_terminator` to pretty stable-mir) - #118202 (Added linker_arg(s) Linker trait methods for link-arg to be prefixed "-Wl," for cc-like linker args and not verbatim) - #118374 (QueryContext: rename try_collect_active_jobs -> collect_active_jobs, change return type from Option<QueryMap> to QueryMap) - #118381 (rustc_span: Use correct edit distance start length for suggestions) - #118382 (Address unused tuple struct fields in the compiler) - #118384 (Address unused tuple struct fields in rustdoc) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
c2ec90854a
33 changed files with 510 additions and 103 deletions
|
@ -756,6 +756,11 @@ impl Token {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the token is the integer literal.
|
||||||
|
pub fn is_integer_lit(&self) -> bool {
|
||||||
|
matches!(self.kind, Literal(Lit { kind: LitKind::Integer, .. }))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the token is a non-raw identifier for which `pred` holds.
|
/// Returns `true` if the token is a non-raw identifier for which `pred` holds.
|
||||||
pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
|
pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
|
||||||
match self.ident() {
|
match self.ident() {
|
||||||
|
|
|
@ -42,6 +42,7 @@ use rustc_target::abi::FieldIdx;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ use renumber::RegionCtxt;
|
||||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
/// Associate some local constants with the `'tcx` lifetime
|
/// Associate some local constants with the `'tcx` lifetime
|
||||||
struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>);
|
struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>);
|
||||||
impl<'tcx> TyCtxtConsts<'tcx> {
|
impl<'tcx> TyCtxtConsts<'tcx> {
|
||||||
const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
|
const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref];
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ use tempfile::Builder as TempFileBuilder;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::ffi::OsString;
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs::{read, File, OpenOptions};
|
use std::fs::{read, File, OpenOptions};
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -2527,7 +2527,7 @@ fn add_native_libs_from_crate(
|
||||||
NativeLibKind::WasmImportModule => {}
|
NativeLibKind::WasmImportModule => {}
|
||||||
NativeLibKind::LinkArg => {
|
NativeLibKind::LinkArg => {
|
||||||
if link_static {
|
if link_static {
|
||||||
cmd.arg(name);
|
cmd.linker_arg(OsStr::new(name), verbatim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,6 +196,14 @@ pub trait Linker {
|
||||||
fn add_no_exec(&mut self) {}
|
fn add_no_exec(&mut self) {}
|
||||||
fn add_as_needed(&mut self) {}
|
fn add_as_needed(&mut self) {}
|
||||||
fn reset_per_library_state(&mut self) {}
|
fn reset_per_library_state(&mut self) {}
|
||||||
|
fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) {
|
||||||
|
self.linker_args(&[arg], verbatim);
|
||||||
|
}
|
||||||
|
fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) {
|
||||||
|
args.into_iter().for_each(|a| {
|
||||||
|
self.cmd().arg(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn Linker + '_ {
|
impl dyn Linker + '_ {
|
||||||
|
@ -223,38 +231,12 @@ pub struct GccLinker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GccLinker<'a> {
|
impl<'a> GccLinker<'a> {
|
||||||
/// Passes an argument directly to the linker.
|
fn linker_arg(&mut self, arg: impl AsRef<OsStr>) {
|
||||||
///
|
Linker::linker_arg(self, arg.as_ref(), false);
|
||||||
/// When the linker is not ld-like such as when using a compiler as a linker, the argument is
|
|
||||||
/// prepended by `-Wl,`.
|
|
||||||
fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self {
|
|
||||||
self.linker_args(&[arg]);
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) {
|
||||||
/// Passes a series of arguments directly to the linker.
|
let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect();
|
||||||
///
|
Linker::linker_args(self, &args_vec, false);
|
||||||
/// When the linker is ld-like, the arguments are simply appended to the command. When the
|
|
||||||
/// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
|
|
||||||
/// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
|
|
||||||
/// single argument is appended to the command to ensure that the order of the arguments is
|
|
||||||
/// preserved by the compiler.
|
|
||||||
fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self {
|
|
||||||
if self.is_ld {
|
|
||||||
args.into_iter().for_each(|a| {
|
|
||||||
self.cmd.arg(a);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if !args.is_empty() {
|
|
||||||
let mut s = OsString::from("-Wl");
|
|
||||||
for a in args {
|
|
||||||
s.push(",");
|
|
||||||
s.push(a);
|
|
||||||
}
|
|
||||||
self.cmd.arg(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn takes_hints(&self) -> bool {
|
fn takes_hints(&self) -> bool {
|
||||||
|
@ -361,6 +343,30 @@ impl<'a> GccLinker<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Linker for GccLinker<'a> {
|
impl<'a> Linker for GccLinker<'a> {
|
||||||
|
/// Passes a series of arguments directly to the linker.
|
||||||
|
///
|
||||||
|
/// When the linker is ld-like, the arguments are simply appended to the command. When the
|
||||||
|
/// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
|
||||||
|
/// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
|
||||||
|
/// single argument is appended to the command to ensure that the order of the arguments is
|
||||||
|
/// preserved by the compiler.
|
||||||
|
fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) {
|
||||||
|
if self.is_ld || verbatim {
|
||||||
|
args.into_iter().for_each(|a| {
|
||||||
|
self.cmd.arg(a);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if !args.is_empty() {
|
||||||
|
let mut s = OsString::from("-Wl");
|
||||||
|
for a in args {
|
||||||
|
s.push(",");
|
||||||
|
s.push(a);
|
||||||
|
}
|
||||||
|
self.cmd.arg(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn cmd(&mut self) -> &mut Command {
|
fn cmd(&mut self) -> &mut Command {
|
||||||
&mut self.cmd
|
&mut self.cmd
|
||||||
}
|
}
|
||||||
|
@ -531,7 +537,7 @@ impl<'a> Linker for GccLinker<'a> {
|
||||||
self.linker_arg("-force_load");
|
self.linker_arg("-force_load");
|
||||||
self.linker_arg(&lib);
|
self.linker_arg(&lib);
|
||||||
} else {
|
} else {
|
||||||
self.linker_arg("--whole-archive").cmd.arg(lib);
|
self.linker_args(&[OsString::from("--whole-archive"), lib.into()]);
|
||||||
self.linker_arg("--no-whole-archive");
|
self.linker_arg("--no-whole-archive");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
&cause,
|
&cause,
|
||||||
Some(arm.body),
|
Some(arm.body),
|
||||||
arm_ty,
|
arm_ty,
|
||||||
|err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm),
|
|err| {
|
||||||
|
self.explain_never_type_coerced_to_unit(err, arm, arm_ty, prior_arm, expr);
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -177,6 +179,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
coercion.complete(self)
|
coercion.complete(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn explain_never_type_coerced_to_unit(
|
||||||
|
&self,
|
||||||
|
err: &mut Diagnostic,
|
||||||
|
arm: &hir::Arm<'tcx>,
|
||||||
|
arm_ty: Ty<'tcx>,
|
||||||
|
prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>,
|
||||||
|
expr: &hir::Expr<'tcx>,
|
||||||
|
) {
|
||||||
|
if let hir::ExprKind::Block(block, _) = arm.body.kind
|
||||||
|
&& let Some(expr) = block.expr
|
||||||
|
&& let arm_tail_ty = self.node_ty(expr.hir_id)
|
||||||
|
&& arm_tail_ty.is_never()
|
||||||
|
&& !arm_ty.is_never()
|
||||||
|
{
|
||||||
|
err.span_label(
|
||||||
|
expr.span,
|
||||||
|
format!(
|
||||||
|
"this expression is of type `!`, but it is coerced to `{arm_ty}` due to its \
|
||||||
|
surrounding expression",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.suggest_mismatched_types_on_tail(
|
||||||
|
err,
|
||||||
|
expr,
|
||||||
|
arm_ty,
|
||||||
|
prior_arm.map_or(arm_tail_ty, |(_, ty, _)| ty),
|
||||||
|
expr.hir_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm)
|
||||||
|
}
|
||||||
|
|
||||||
fn suggest_removing_semicolon_for_coerce(
|
fn suggest_removing_semicolon_for_coerce(
|
||||||
&self,
|
&self,
|
||||||
diag: &mut Diagnostic,
|
diag: &mut Diagnostic,
|
||||||
|
|
|
@ -1715,6 +1715,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
||||||
// label pointing out the cause for the type coercion will be wrong
|
// label pointing out the cause for the type coercion will be wrong
|
||||||
// as prior return coercions would not be relevant (#57664).
|
// as prior return coercions would not be relevant (#57664).
|
||||||
let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
|
let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
|
||||||
|
fcx.suggest_missing_semicolon(&mut err, expr, expected, false);
|
||||||
let pointing_at_return_type =
|
let pointing_at_return_type =
|
||||||
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
|
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
|
||||||
if let (Some(cond_expr), true, false) = (
|
if let (Some(cond_expr), true, false) = (
|
||||||
|
|
|
@ -663,8 +663,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
coerce.coerce_forced_unit(
|
coerce.coerce_forced_unit(
|
||||||
self,
|
self,
|
||||||
&cause,
|
&cause,
|
||||||
|err| {
|
|mut err| {
|
||||||
self.suggest_mismatched_types_on_tail(err, expr, ty, e_ty, target_id);
|
self.suggest_missing_semicolon(&mut err, expr, e_ty, false);
|
||||||
|
self.suggest_mismatched_types_on_tail(
|
||||||
|
&mut err, expr, ty, e_ty, target_id,
|
||||||
|
);
|
||||||
let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
|
let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty }));
|
||||||
self.annotate_loop_expected_due_to_inference(err, expr, error);
|
self.annotate_loop_expected_due_to_inference(err, expr, error);
|
||||||
if let Some(val) = ty_kind_suggestion(ty) {
|
if let Some(val) = ty_kind_suggestion(ty) {
|
||||||
|
|
|
@ -72,7 +72,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
blk_id: hir::HirId,
|
blk_id: hir::HirId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let expr = expr.peel_drop_temps();
|
let expr = expr.peel_drop_temps();
|
||||||
self.suggest_missing_semicolon(err, expr, expected, false);
|
|
||||||
let mut pointing_at_return_type = false;
|
let mut pointing_at_return_type = false;
|
||||||
if let hir::ExprKind::Break(..) = expr.kind {
|
if let hir::ExprKind::Break(..) = expr.kind {
|
||||||
// `break` type mismatches provide better context for tail `loop` expressions.
|
// `break` type mismatches provide better context for tail `loop` expressions.
|
||||||
|
|
|
@ -126,11 +126,8 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
||||||
.deadlock_handler(|| {
|
.deadlock_handler(|| {
|
||||||
// On deadlock, creates a new thread and forwards information in thread
|
// On deadlock, creates a new thread and forwards information in thread
|
||||||
// locals to it. The new thread runs the deadlock handler.
|
// locals to it. The new thread runs the deadlock handler.
|
||||||
let query_map = FromDyn::from(tls::with(|tcx| {
|
let query_map =
|
||||||
QueryCtxt::new(tcx)
|
FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs()));
|
||||||
.try_collect_active_jobs()
|
|
||||||
.expect("active jobs shouldn't be locked in deadlock handler")
|
|
||||||
}));
|
|
||||||
let registry = rayon_core::Registry::current();
|
let registry = rayon_core::Registry::current();
|
||||||
thread::spawn(move || deadlock(query_map.into_inner(), ®istry));
|
thread::spawn(move || deadlock(query_map.into_inner(), ®istry));
|
||||||
});
|
});
|
||||||
|
|
|
@ -385,7 +385,7 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||||
enum Context {
|
enum Context {
|
||||||
Safe,
|
Safe,
|
||||||
/// in an `unsafe fn`
|
/// in an `unsafe fn`
|
||||||
UnsafeFn(HirId),
|
UnsafeFn,
|
||||||
/// in a *used* `unsafe` block
|
/// in a *used* `unsafe` block
|
||||||
/// (i.e. a block without unused-unsafe warning)
|
/// (i.e. a block without unused-unsafe warning)
|
||||||
UnsafeBlock(HirId),
|
UnsafeBlock(HirId),
|
||||||
|
@ -407,7 +407,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
|
||||||
};
|
};
|
||||||
let unused_unsafe = match (self.context, used) {
|
let unused_unsafe = match (self.context, used) {
|
||||||
(_, false) => UnusedUnsafe::Unused,
|
(_, false) => UnusedUnsafe::Unused,
|
||||||
(Context::Safe, true) | (Context::UnsafeFn(_), true) => {
|
(Context::Safe, true) | (Context::UnsafeFn, true) => {
|
||||||
let previous_context = self.context;
|
let previous_context = self.context;
|
||||||
self.context = Context::UnsafeBlock(block.hir_id);
|
self.context = Context::UnsafeBlock(block.hir_id);
|
||||||
intravisit::walk_block(self, block);
|
intravisit::walk_block(self, block);
|
||||||
|
@ -454,7 +454,7 @@ fn check_unused_unsafe(
|
||||||
let body = tcx.hir().body(body_id);
|
let body = tcx.hir().body(body_id);
|
||||||
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
let hir_id = tcx.local_def_id_to_hir_id(def_id);
|
||||||
let context = match tcx.hir().fn_sig_by_hir_id(hir_id) {
|
let context = match tcx.hir().fn_sig_by_hir_id(hir_id) {
|
||||||
Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn(hir_id),
|
Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn,
|
||||||
_ => Context::Safe,
|
_ => Context::Safe,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -567,20 +567,37 @@ impl<'a> Parser<'a> {
|
||||||
snapshot.recover_diff_marker();
|
snapshot.recover_diff_marker();
|
||||||
}
|
}
|
||||||
if self.token == token::Colon {
|
if self.token == token::Colon {
|
||||||
// if next token is following a colon, it's likely a path
|
// if a previous and next token of the current one is
|
||||||
// and we can suggest a path separator
|
// integer literal (e.g. `1:42`), it's likely a range
|
||||||
self.bump();
|
// expression for Pythonistas and we can suggest so.
|
||||||
if self.token.span.lo() == self.prev_token.span.hi() {
|
if self.prev_token.is_integer_lit()
|
||||||
|
&& self.may_recover()
|
||||||
|
&& self.look_ahead(1, |token| token.is_integer_lit())
|
||||||
|
{
|
||||||
|
// FIXME(hkmatsumoto): Might be better to trigger
|
||||||
|
// this only when parsing an index expression.
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
self.prev_token.span,
|
self.token.span,
|
||||||
"maybe write a path separator here",
|
"you might have meant a range expression",
|
||||||
"::",
|
"..",
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
if self.sess.unstable_features.is_nightly_build() {
|
// if next token is following a colon, it's likely a path
|
||||||
// FIXME(Nilstrieb): Remove this again after a few months.
|
// and we can suggest a path separator
|
||||||
err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>");
|
self.bump();
|
||||||
|
if self.token.span.lo() == self.prev_token.span.hi() {
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
self.prev_token.span,
|
||||||
|
"maybe write a path separator here",
|
||||||
|
"::",
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if self.sess.unstable_features.is_nightly_build() {
|
||||||
|
// FIXME(Nilstrieb): Remove this again after a few months.
|
||||||
|
err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,14 +80,14 @@ impl QueryContext for QueryCtxt<'_> {
|
||||||
tls::with_related_context(self.tcx, |icx| icx.query)
|
tls::with_related_context(self.tcx, |icx| icx.query)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_collect_active_jobs(self) -> Option<QueryMap> {
|
fn collect_active_jobs(self) -> QueryMap {
|
||||||
let mut jobs = QueryMap::default();
|
let mut jobs = QueryMap::default();
|
||||||
|
|
||||||
for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() {
|
for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() {
|
||||||
collect(self.tcx, &mut jobs);
|
collect(self.tcx, &mut jobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(jobs)
|
jobs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interactions with on_disk_cache
|
// Interactions with on_disk_cache
|
||||||
|
@ -155,11 +155,11 @@ impl QueryContext for QueryCtxt<'_> {
|
||||||
fn depth_limit_error(self, job: QueryJobId) {
|
fn depth_limit_error(self, job: QueryJobId) {
|
||||||
let mut span = None;
|
let mut span = None;
|
||||||
let mut layout_of_depth = None;
|
let mut layout_of_depth = None;
|
||||||
if let Some(map) = self.try_collect_active_jobs() {
|
if let Some((info, depth)) =
|
||||||
if let Some((info, depth)) = job.try_find_layout_root(map, dep_kinds::layout_of) {
|
job.try_find_layout_root(self.collect_active_jobs(), dep_kinds::layout_of)
|
||||||
span = Some(info.job.span);
|
{
|
||||||
layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth });
|
span = Some(info.job.span);
|
||||||
}
|
layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth });
|
||||||
}
|
}
|
||||||
|
|
||||||
let suggested_limit = match self.recursion_limit() {
|
let suggested_limit = match self.recursion_limit() {
|
||||||
|
|
|
@ -620,13 +620,13 @@ pub fn print_query_stack<Qcx: QueryContext>(
|
||||||
// state if it was responsible for triggering the panic.
|
// state if it was responsible for triggering the panic.
|
||||||
let mut count_printed = 0;
|
let mut count_printed = 0;
|
||||||
let mut count_total = 0;
|
let mut count_total = 0;
|
||||||
let query_map = qcx.try_collect_active_jobs();
|
let query_map = qcx.collect_active_jobs();
|
||||||
|
|
||||||
if let Some(ref mut file) = file {
|
if let Some(ref mut file) = file {
|
||||||
let _ = writeln!(file, "\n\nquery stack during panic:");
|
let _ = writeln!(file, "\n\nquery stack during panic:");
|
||||||
}
|
}
|
||||||
while let Some(query) = current_query {
|
while let Some(query) = current_query {
|
||||||
let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else {
|
let Some(query_info) = query_map.get(&query) else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
if Some(count_printed) < num_frames || num_frames.is_none() {
|
if Some(count_printed) < num_frames || num_frames.is_none() {
|
||||||
|
|
|
@ -106,7 +106,7 @@ pub trait QueryContext: HasDepContext {
|
||||||
/// Get the query information from the TLS context.
|
/// Get the query information from the TLS context.
|
||||||
fn current_query_job(self) -> Option<QueryJobId>;
|
fn current_query_job(self) -> Option<QueryJobId>;
|
||||||
|
|
||||||
fn try_collect_active_jobs(self) -> Option<QueryMap>;
|
fn collect_active_jobs(self) -> QueryMap;
|
||||||
|
|
||||||
/// Load side effects associated to the node in the previous session.
|
/// Load side effects associated to the node in the previous session.
|
||||||
fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
|
fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
|
||||||
|
|
|
@ -242,11 +242,8 @@ where
|
||||||
Q: QueryConfig<Qcx>,
|
Q: QueryConfig<Qcx>,
|
||||||
Qcx: QueryContext,
|
Qcx: QueryContext,
|
||||||
{
|
{
|
||||||
let error = try_execute.find_cycle_in_stack(
|
let error =
|
||||||
qcx.try_collect_active_jobs().unwrap(),
|
try_execute.find_cycle_in_stack(qcx.collect_active_jobs(), &qcx.current_query_job(), span);
|
||||||
&qcx.current_query_job(),
|
|
||||||
span,
|
|
||||||
);
|
|
||||||
(mk_cycle(query, qcx, error), None)
|
(mk_cycle(query, qcx, error), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// In that case, the impl-trait is lowered as an additional generic parameter.
|
// In that case, the impl-trait is lowered as an additional generic parameter.
|
||||||
self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| {
|
self.with_impl_trait(ImplTraitContext::Universal, |this| {
|
||||||
visit::walk_generic_param(this, param)
|
visit::walk_generic_param(this, param)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -310,9 +310,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||||
if p.is_placeholder {
|
if p.is_placeholder {
|
||||||
self.visit_macro_invoc(p.id)
|
self.visit_macro_invoc(p.id)
|
||||||
} else {
|
} else {
|
||||||
self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| {
|
self.with_impl_trait(ImplTraitContext::Universal, |this| visit::walk_param(this, p))
|
||||||
visit::walk_param(this, p)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,7 @@ impl<'a> ParentScope<'a> {
|
||||||
#[derive(Copy, Debug, Clone)]
|
#[derive(Copy, Debug, Clone)]
|
||||||
enum ImplTraitContext {
|
enum ImplTraitContext {
|
||||||
Existential,
|
Existential,
|
||||||
Universal(LocalDefId),
|
Universal,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -578,13 +578,13 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> {
|
||||||
}
|
}
|
||||||
mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
|
mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt {
|
||||||
discr: discr.stable(tables),
|
discr: discr.stable(tables),
|
||||||
targets: targets
|
targets: {
|
||||||
.iter()
|
let (value_vec, mut target_vec): (Vec<_>, Vec<_>) =
|
||||||
.map(|(value, target)| stable_mir::mir::SwitchTarget {
|
targets.iter().map(|(value, target)| (value, target.as_usize())).unzip();
|
||||||
value,
|
// We need to push otherwise as last element to ensure it's same as in MIR.
|
||||||
target: target.as_usize(),
|
target_vec.push(targets.otherwise().as_usize());
|
||||||
})
|
stable_mir::mir::SwitchTargets { value: value_vec, targets: target_vec }
|
||||||
.collect(),
|
},
|
||||||
otherwise: targets.otherwise().as_usize(),
|
otherwise: targets.otherwise().as_usize(),
|
||||||
},
|
},
|
||||||
mir::TerminatorKind::UnwindResume => TerminatorKind::Resume,
|
mir::TerminatorKind::UnwindResume => TerminatorKind::Resume,
|
||||||
|
|
|
@ -188,7 +188,11 @@ fn find_best_match_for_name_impl(
|
||||||
return Some(*c);
|
return Some(*c);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
|
// `fn edit_distance()` use `chars()` to calculate edit distance, so we must
|
||||||
|
// also use `chars()` (and not `str::len()`) to calculate length here.
|
||||||
|
let lookup_len = lookup.chars().count();
|
||||||
|
|
||||||
|
let mut dist = dist.unwrap_or_else(|| cmp::max(lookup_len, 3) / 3);
|
||||||
let mut best = None;
|
let mut best = None;
|
||||||
// store the candidates with the same distance, only for `use_substring_score` current.
|
// store the candidates with the same distance, only for `use_substring_score` current.
|
||||||
let mut next_candidates = vec![];
|
let mut next_candidates = vec![];
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
//!
|
//!
|
||||||
//! The goal is to eventually be published on
|
//! The goal is to eventually be published on
|
||||||
//! [crates.io](https://crates.io).
|
//! [crates.io](https://crates.io).
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate scoped_tls;
|
extern crate scoped_tls;
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ impl std::fmt::Display for Opaque {
|
||||||
|
|
||||||
impl std::fmt::Debug for Opaque {
|
impl std::fmt::Debug for Opaque {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{:?}", self.0)
|
write!(f, "{}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use crate::mir::pretty::{function_body, pretty_statement};
|
use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator};
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
|
AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
|
||||||
};
|
};
|
||||||
use crate::{Error, Opaque, Span, Symbol};
|
use crate::{Error, Opaque, Span, Symbol};
|
||||||
use std::io;
|
use std::{io, slice};
|
||||||
|
|
||||||
/// The SMIR representation of a single function.
|
/// The SMIR representation of a single function.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
|
@ -83,6 +82,8 @@ impl Body {
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
pretty_terminator(&block.terminator.kind, w)?;
|
||||||
|
writeln!(w, "").unwrap();
|
||||||
writeln!(w, " }}").unwrap();
|
writeln!(w, " }}").unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -100,7 +101,7 @@ pub struct LocalDecl {
|
||||||
pub mutability: Mutability,
|
pub mutability: Mutability,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct BasicBlock {
|
pub struct BasicBlock {
|
||||||
pub statements: Vec<Statement>,
|
pub statements: Vec<Statement>,
|
||||||
pub terminator: Terminator,
|
pub terminator: Terminator,
|
||||||
|
@ -112,6 +113,14 @@ pub struct Terminator {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Terminator {
|
||||||
|
pub fn successors(&self) -> Successors<'_> {
|
||||||
|
self.kind.successors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Successors<'a> = impl Iterator<Item = usize> + 'a;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum TerminatorKind {
|
pub enum TerminatorKind {
|
||||||
Goto {
|
Goto {
|
||||||
|
@ -119,7 +128,7 @@ pub enum TerminatorKind {
|
||||||
},
|
},
|
||||||
SwitchInt {
|
SwitchInt {
|
||||||
discr: Operand,
|
discr: Operand,
|
||||||
targets: Vec<SwitchTarget>,
|
targets: SwitchTargets,
|
||||||
otherwise: usize,
|
otherwise: usize,
|
||||||
},
|
},
|
||||||
Resume,
|
Resume,
|
||||||
|
@ -156,6 +165,58 @@ pub enum TerminatorKind {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TerminatorKind {
|
||||||
|
pub fn successors(&self) -> Successors<'_> {
|
||||||
|
use self::TerminatorKind::*;
|
||||||
|
match *self {
|
||||||
|
Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. }
|
||||||
|
| Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
||||||
|
| Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. }
|
||||||
|
| InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => {
|
||||||
|
Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied())
|
||||||
|
}
|
||||||
|
Goto { target: t }
|
||||||
|
| Call { target: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||||
|
| Call { target: Some(t), unwind: _, .. }
|
||||||
|
| Drop { target: t, unwind: _, .. }
|
||||||
|
| Assert { target: t, unwind: _, .. }
|
||||||
|
| InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. }
|
||||||
|
| InlineAsm { destination: Some(t), unwind: _, .. } => {
|
||||||
|
Some(t).into_iter().chain((&[]).into_iter().copied())
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineDrop
|
||||||
|
| Return
|
||||||
|
| Resume
|
||||||
|
| Abort
|
||||||
|
| Unreachable
|
||||||
|
| Call { target: None, unwind: _, .. }
|
||||||
|
| InlineAsm { destination: None, unwind: _, .. } => {
|
||||||
|
None.into_iter().chain((&[]).into_iter().copied())
|
||||||
|
}
|
||||||
|
SwitchInt { ref targets, .. } => {
|
||||||
|
None.into_iter().chain(targets.targets.iter().copied())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwind(&self) -> Option<&UnwindAction> {
|
||||||
|
match *self {
|
||||||
|
TerminatorKind::Goto { .. }
|
||||||
|
| TerminatorKind::Return
|
||||||
|
| TerminatorKind::Unreachable
|
||||||
|
| TerminatorKind::CoroutineDrop
|
||||||
|
| TerminatorKind::Resume
|
||||||
|
| TerminatorKind::Abort
|
||||||
|
| TerminatorKind::SwitchInt { .. } => None,
|
||||||
|
TerminatorKind::Call { ref unwind, .. }
|
||||||
|
| TerminatorKind::Assert { ref unwind, .. }
|
||||||
|
| TerminatorKind::Drop { ref unwind, .. }
|
||||||
|
| TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct InlineAsmOperand {
|
pub struct InlineAsmOperand {
|
||||||
pub in_value: Option<Operand>,
|
pub in_value: Option<Operand>,
|
||||||
|
@ -602,9 +663,9 @@ pub struct Constant {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct SwitchTarget {
|
pub struct SwitchTargets {
|
||||||
pub value: u128,
|
pub value: Vec<u128>,
|
||||||
pub target: usize,
|
pub targets: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
use crate::crate_def::CrateDef;
|
use crate::crate_def::CrateDef;
|
||||||
use crate::mir::{Operand, Rvalue, StatementKind};
|
use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction};
|
||||||
use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
|
use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
|
||||||
use crate::{with, Body, CrateItem, Mutability};
|
use crate::{with, Body, CrateItem, Mutability};
|
||||||
|
use std::io::Write;
|
||||||
|
use std::{io, iter};
|
||||||
|
|
||||||
|
use super::{AssertMessage, BinOp, TerminatorKind};
|
||||||
|
|
||||||
pub fn function_name(item: CrateItem) -> String {
|
pub fn function_name(item: CrateItem) -> String {
|
||||||
let mut pretty_name = String::new();
|
let mut pretty_name = String::new();
|
||||||
|
@ -70,6 +74,209 @@ pub fn pretty_statement(statement: &StatementKind) -> String {
|
||||||
pretty
|
pretty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> {
|
||||||
|
write!(w, "{}", pretty_terminator_head(terminator))?;
|
||||||
|
let successor_count = terminator.successors().count();
|
||||||
|
let labels = pretty_successor_labels(terminator);
|
||||||
|
|
||||||
|
let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_)));
|
||||||
|
let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> {
|
||||||
|
write!(fmt, "unwind ")?;
|
||||||
|
match terminator.unwind() {
|
||||||
|
None | Some(UnwindAction::Cleanup(_)) => unreachable!(),
|
||||||
|
Some(UnwindAction::Continue) => write!(fmt, "continue"),
|
||||||
|
Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"),
|
||||||
|
Some(UnwindAction::Terminate) => write!(fmt, "terminate"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match (successor_count, show_unwind) {
|
||||||
|
(0, false) => Ok(()),
|
||||||
|
(0, true) => {
|
||||||
|
write!(w, " -> ")?;
|
||||||
|
fmt_unwind(w)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
(1, false) => {
|
||||||
|
write!(w, " -> {:?}", terminator.successors().next().unwrap())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
write!(w, " -> [")?;
|
||||||
|
for (i, target) in terminator.successors().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
write!(w, ", ")?;
|
||||||
|
}
|
||||||
|
write!(w, "{}: bb{:?}", labels[i], target)?;
|
||||||
|
}
|
||||||
|
if show_unwind {
|
||||||
|
write!(w, ", ")?;
|
||||||
|
fmt_unwind(w)?;
|
||||||
|
}
|
||||||
|
write!(w, "]")
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String {
|
||||||
|
use self::TerminatorKind::*;
|
||||||
|
let mut pretty = String::new();
|
||||||
|
match terminator {
|
||||||
|
Goto { .. } => format!(" goto"),
|
||||||
|
SwitchInt { discr, .. } => {
|
||||||
|
format!(" switchInt(_{})", pretty_operand(discr))
|
||||||
|
}
|
||||||
|
Resume => format!(" resume"),
|
||||||
|
Abort => format!(" abort"),
|
||||||
|
Return => format!(" return"),
|
||||||
|
Unreachable => format!(" unreachable"),
|
||||||
|
Drop { place, .. } => format!(" drop(_{:?})", place.local),
|
||||||
|
Call { func, args, destination, .. } => {
|
||||||
|
pretty.push_str(" ");
|
||||||
|
pretty.push_str(format!("_{} = ", destination.local).as_str());
|
||||||
|
pretty.push_str(&pretty_operand(func));
|
||||||
|
pretty.push_str("(");
|
||||||
|
args.iter().enumerate().for_each(|(i, arg)| {
|
||||||
|
if i > 0 {
|
||||||
|
pretty.push_str(", ");
|
||||||
|
}
|
||||||
|
pretty.push_str(&pretty_operand(arg));
|
||||||
|
});
|
||||||
|
pretty.push_str(")");
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
Assert { cond, expected, msg, target: _, unwind: _ } => {
|
||||||
|
pretty.push_str(" assert(");
|
||||||
|
if !expected {
|
||||||
|
pretty.push_str("!");
|
||||||
|
}
|
||||||
|
pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str());
|
||||||
|
pretty.push_str(&pretty_assert_message(msg));
|
||||||
|
pretty.push_str(")");
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
CoroutineDrop => format!(" coroutine_drop"),
|
||||||
|
InlineAsm { .. } => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> {
|
||||||
|
use self::TerminatorKind::*;
|
||||||
|
match terminator {
|
||||||
|
Resume | Abort | Return | Unreachable | CoroutineDrop => vec![],
|
||||||
|
Goto { .. } => vec!["".to_string()],
|
||||||
|
SwitchInt { targets, .. } => targets
|
||||||
|
.value
|
||||||
|
.iter()
|
||||||
|
.map(|target| format!("{}", target))
|
||||||
|
.chain(iter::once("otherwise".into()))
|
||||||
|
.collect(),
|
||||||
|
Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()],
|
||||||
|
Drop { unwind: _, .. } => vec!["return".into()],
|
||||||
|
Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
|
vec!["return".into(), "unwind".into()]
|
||||||
|
}
|
||||||
|
Call { target: Some(_), unwind: _, .. } => vec!["return".into()],
|
||||||
|
Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()],
|
||||||
|
Call { target: None, unwind: _, .. } => vec![],
|
||||||
|
Assert { unwind: UnwindAction::Cleanup(_), .. } => {
|
||||||
|
vec!["success".into(), "unwind".into()]
|
||||||
|
}
|
||||||
|
Assert { unwind: _, .. } => vec!["success".into()],
|
||||||
|
InlineAsm { .. } => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pretty_assert_message(msg: &AssertMessage) -> String {
|
||||||
|
let mut pretty = String::new();
|
||||||
|
match msg {
|
||||||
|
AssertMessage::BoundsCheck { len, index } => {
|
||||||
|
let pretty_len = pretty_operand(len);
|
||||||
|
let pretty_index = pretty_operand(index);
|
||||||
|
pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::Overflow(BinOp::Add, l, r) => {
|
||||||
|
let pretty_l = pretty_operand(l);
|
||||||
|
let pretty_r = pretty_operand(r);
|
||||||
|
pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::Overflow(BinOp::Sub, l, r) => {
|
||||||
|
let pretty_l = pretty_operand(l);
|
||||||
|
let pretty_r = pretty_operand(r);
|
||||||
|
pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::Overflow(BinOp::Mul, l, r) => {
|
||||||
|
let pretty_l = pretty_operand(l);
|
||||||
|
let pretty_r = pretty_operand(r);
|
||||||
|
pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::Overflow(BinOp::Div, l, r) => {
|
||||||
|
let pretty_l = pretty_operand(l);
|
||||||
|
let pretty_r = pretty_operand(r);
|
||||||
|
pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::Overflow(BinOp::Rem, l, r) => {
|
||||||
|
let pretty_l = pretty_operand(l);
|
||||||
|
let pretty_r = pretty_operand(r);
|
||||||
|
pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::Overflow(BinOp::Shr, _, r) => {
|
||||||
|
let pretty_r = pretty_operand(r);
|
||||||
|
pretty.push_str(
|
||||||
|
format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}")
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::Overflow(BinOp::Shl, _, r) => {
|
||||||
|
let pretty_r = pretty_operand(r);
|
||||||
|
pretty.push_str(
|
||||||
|
format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}")
|
||||||
|
.as_str(),
|
||||||
|
);
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::OverflowNeg(op) => {
|
||||||
|
let pretty_op = pretty_operand(op);
|
||||||
|
pretty.push_str(
|
||||||
|
format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(),
|
||||||
|
);
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::DivisionByZero(op) => {
|
||||||
|
let pretty_op = pretty_operand(op);
|
||||||
|
pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::RemainderByZero(op) => {
|
||||||
|
let pretty_op = pretty_operand(op);
|
||||||
|
pretty.push_str(
|
||||||
|
format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(),
|
||||||
|
);
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
AssertMessage::ResumedAfterReturn(_) => {
|
||||||
|
format!("attempt to resume a generator after completion")
|
||||||
|
}
|
||||||
|
AssertMessage::ResumedAfterPanic(_) => format!("attempt to resume a panicked generator"),
|
||||||
|
AssertMessage::MisalignedPointerDereference { required, found } => {
|
||||||
|
let pretty_required = pretty_operand(required);
|
||||||
|
let pretty_found = pretty_operand(found);
|
||||||
|
pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str());
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pretty_operand(operand: &Operand) -> String {
|
pub fn pretty_operand(operand: &Operand) -> String {
|
||||||
let mut pretty = String::new();
|
let mut pretty = String::new();
|
||||||
match operand {
|
match operand {
|
||||||
|
|
|
@ -1821,11 +1821,8 @@ fn maybe_expand_private_type_alias<'tcx>(
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
if let Some(ct) = const_ {
|
if let Some(_) = const_ {
|
||||||
args.insert(
|
args.insert(param.def_id.to_def_id(), SubstParam::Constant);
|
||||||
param.def_id.to_def_id(),
|
|
||||||
SubstParam::Constant(clean_const(ct, cx)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// FIXME(const_generics_defaults)
|
// FIXME(const_generics_defaults)
|
||||||
indices.consts += 1;
|
indices.consts += 1;
|
||||||
|
|
|
@ -2546,7 +2546,7 @@ pub(crate) enum TypeBindingKind {
|
||||||
pub(crate) enum SubstParam {
|
pub(crate) enum SubstParam {
|
||||||
Type(Type),
|
Type(Type),
|
||||||
Lifetime(Lifetime),
|
Lifetime(Lifetime),
|
||||||
Constant(Constant),
|
Constant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubstParam {
|
impl SubstParam {
|
||||||
|
|
8
tests/run-make/pass-linker-flags-flavor/Makefile
Normal file
8
tests/run-make/pass-linker-flags-flavor/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# only-linux
|
||||||
|
|
||||||
|
include ../tools.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*-Wl,a1.*l2.*-Wl,a2.*d1.*-Wl,a3'
|
||||||
|
$(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg:+verbatim=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*-Wl,a2.*d1.*-Wl,a3'
|
||||||
|
$(RUSTC) rs.rs -Z unstable-options -C linker-flavor=ld -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*"a2".*d1.*"a3"'
|
1
tests/run-make/pass-linker-flags-flavor/rs.rs
Normal file
1
tests/run-make/pass-linker-flags-flavor/rs.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
fn main() {}
|
16
tests/ui/match/match-tail-expr-never-type-error.rs
Normal file
16
tests/ui/match/match-tail-expr-never-type-error.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
fn never() -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(a: bool) {
|
||||||
|
match a {
|
||||||
|
true => 1,
|
||||||
|
false => {
|
||||||
|
never() //~ ERROR `match` arms have incompatible types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
bar(true);
|
||||||
|
bar(false);
|
||||||
|
}
|
21
tests/ui/match/match-tail-expr-never-type-error.stderr
Normal file
21
tests/ui/match/match-tail-expr-never-type-error.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0308]: `match` arms have incompatible types
|
||||||
|
--> $DIR/match-tail-expr-never-type-error.rs:9:13
|
||||||
|
|
|
||||||
|
LL | fn bar(a: bool) {
|
||||||
|
| - help: try adding a return type: `-> i32`
|
||||||
|
LL | / match a {
|
||||||
|
LL | | true => 1,
|
||||||
|
| | - this is found to be of type `{integer}`
|
||||||
|
LL | | false => {
|
||||||
|
LL | | never()
|
||||||
|
| | ^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | expected integer, found `()`
|
||||||
|
| | this expression is of type `!`, but it is coerced to `()` due to its surrounding expression
|
||||||
|
LL | | }
|
||||||
|
LL | | }
|
||||||
|
| |_____- `match` arms have incompatible types
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
4
tests/ui/suggestions/non_ascii_ident.rs
Normal file
4
tests/ui/suggestions/non_ascii_ident.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
// There shall be no suggestions here. In particular not `Ok`.
|
||||||
|
let _ = 读文; //~ ERROR cannot find value `读文` in this scope
|
||||||
|
}
|
9
tests/ui/suggestions/non_ascii_ident.stderr
Normal file
9
tests/ui/suggestions/non_ascii_ident.stderr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0425]: cannot find value `读文` in this scope
|
||||||
|
--> $DIR/non_ascii_ident.rs:3:13
|
||||||
|
|
|
||||||
|
LL | let _ = 读文;
|
||||||
|
| ^^^^ not found in this scope
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0425`.
|
7
tests/ui/suggestions/range-index-instead-of-colon.rs
Normal file
7
tests/ui/suggestions/range-index-instead-of-colon.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// edition:2021
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
&[1, 2, 3][1:2];
|
||||||
|
//~^ ERROR: expected one of
|
||||||
|
//~| HELP: you might have meant a range expression
|
||||||
|
}
|
13
tests/ui/suggestions/range-index-instead-of-colon.stderr
Normal file
13
tests/ui/suggestions/range-index-instead-of-colon.stderr
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
error: expected one of `.`, `?`, `]`, or an operator, found `:`
|
||||||
|
--> $DIR/range-index-instead-of-colon.rs:4:17
|
||||||
|
|
|
||||||
|
LL | &[1, 2, 3][1:2];
|
||||||
|
| ^ expected one of `.`, `?`, `]`, or an operator
|
||||||
|
|
|
||||||
|
help: you might have meant a range expression
|
||||||
|
|
|
||||||
|
LL | &[1, 2, 3][1..2];
|
||||||
|
| ~~
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
|
@ -18,6 +18,7 @@ allow-unauthenticated = [
|
||||||
"relnotes",
|
"relnotes",
|
||||||
"requires-*",
|
"requires-*",
|
||||||
"regression-*",
|
"regression-*",
|
||||||
|
"rla-*",
|
||||||
"perf-*",
|
"perf-*",
|
||||||
"AsyncAwait-OnDeck",
|
"AsyncAwait-OnDeck",
|
||||||
"needs-triage",
|
"needs-triage",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue