Auto merge of #121870 - matthiaskrgr:rollup-mfpa3jx, r=matthiaskrgr
Rollup of 11 pull requests Successful merges: - #111505 (Made `INVALID_DOC_ATTRIBUTES` lint deny by default) - #120305 (Delete line if suggestion would replace it with an empty line) - #121153 (Suggest removing superfluous semicolon when statements used as expression) - #121497 (`-Znext-solver=coherence`: suggest increasing recursion limit) - #121634 (Clarify behavior of slice prefix/suffix operations in case of equality) - #121706 (match lowering: Remove hacky branch in sort_candidate) - #121730 (Add profiling support to AIX) - #121750 (match lowering: Separate the `bool` case from other integers in `TestKind`) - #121803 (Never say "`Trait` is implemented for `{type error}`") - #121811 (Move sanitizer ui tests to sanitizer directory) - #121824 (Implement missing ABI structures in StableMIR) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
eaee1e9453
@ -1631,7 +1631,9 @@ fn no_gc_sections(&mut self) {
|
||||
|
||||
fn optimize(&mut self) {}
|
||||
|
||||
fn pgo_gen(&mut self) {}
|
||||
fn pgo_gen(&mut self) {
|
||||
self.cmd.arg("-bdbg:namedsects:ss");
|
||||
}
|
||||
|
||||
fn control_flow_guard(&mut self) {}
|
||||
|
||||
|
@ -428,7 +428,7 @@ fn from_span_etc(
|
||||
}
|
||||
|
||||
fn from_span_full(
|
||||
span: Span,
|
||||
mut span: Span,
|
||||
is_primary: bool,
|
||||
label: Option<String>,
|
||||
suggestion: Option<(&String, Applicability)>,
|
||||
@ -436,6 +436,16 @@ fn from_span_full(
|
||||
je: &JsonEmitter,
|
||||
) -> DiagnosticSpan {
|
||||
let start = je.sm.lookup_char_pos(span.lo());
|
||||
// If this goes from the start of a line to the end and the replacement
|
||||
// is an empty string, increase the length to include the newline so we don't
|
||||
// leave an empty line
|
||||
if start.col.0 == 0
|
||||
&& suggestion.map_or(false, |(s, _)| s.is_empty())
|
||||
&& let Ok(after) = je.sm.span_to_next_source(span)
|
||||
&& after.starts_with('\n')
|
||||
{
|
||||
span = span.with_hi(span.hi() + rustc_span::BytePos(1));
|
||||
}
|
||||
let end = je.sm.lookup_char_pos(span.hi());
|
||||
let backtrace_step = backtrace.next().map(|bt| {
|
||||
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
|
||||
|
@ -1744,7 +1744,11 @@ pub(in super::super) fn check_block_with_expected(
|
||||
Ty::new_unit(self.tcx),
|
||||
);
|
||||
}
|
||||
if !self.consider_removing_semicolon(blk, expected_ty, err) {
|
||||
if !self.err_ctxt().consider_removing_semicolon(
|
||||
blk,
|
||||
expected_ty,
|
||||
err,
|
||||
) {
|
||||
self.err_ctxt().consider_returning_binding(
|
||||
blk,
|
||||
expected_ty,
|
||||
|
@ -22,7 +22,7 @@
|
||||
Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||
};
|
||||
use rustc_hir_analysis::astconv::AstConv;
|
||||
use rustc_infer::traits::{self, StatementAsExpression};
|
||||
use rustc_infer::traits::{self};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
@ -1791,45 +1791,6 @@ fn note_type_is_not_clone_inner_expr<'b>(
|
||||
}
|
||||
}
|
||||
|
||||
/// A common error is to add an extra semicolon:
|
||||
///
|
||||
/// ```compile_fail,E0308
|
||||
/// fn foo() -> usize {
|
||||
/// 22;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This routine checks if the final statement in a block is an
|
||||
/// expression with an explicit semicolon whose type is compatible
|
||||
/// with `expected_ty`. If so, it suggests removing the semicolon.
|
||||
pub(crate) fn consider_removing_semicolon(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
) -> bool {
|
||||
if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) {
|
||||
if let StatementAsExpression::NeedsBoxing = boxed {
|
||||
err.span_suggestion_verbose(
|
||||
span_semi,
|
||||
"consider removing this semicolon and boxing the expression",
|
||||
"",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_short(
|
||||
span_semi,
|
||||
"remove this semicolon to return this value",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_field_suggestable(
|
||||
&self,
|
||||
field: &ty::FieldDef,
|
||||
|
@ -1989,6 +1989,7 @@ enum Similar<'tcx> {
|
||||
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
|
||||
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
|
||||
self.suggest_function_pointers(cause, span, &exp_found, diag);
|
||||
self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,13 @@
|
||||
use crate::infer::error_reporting::hir::Path;
|
||||
use hir::def::CtorKind;
|
||||
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
|
||||
use hir::{Local, QPath};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::MatchSource;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::traits::{
|
||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||
StatementAsExpression,
|
||||
@ -293,6 +298,97 @@ pub(super) fn suggest_accessing_field_where_appropriate(
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn suggest_turning_stmt_into_expr(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
|
||||
diag: &mut Diag<'_>,
|
||||
) {
|
||||
let ty::error::ExpectedFound { expected, found } = exp_found;
|
||||
if !found.peel_refs().is_unit() {
|
||||
return;
|
||||
}
|
||||
|
||||
let ObligationCauseCode::BlockTailExpression(hir_id, MatchSource::Normal) = cause.code()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let node = self.tcx.hir_node(*hir_id);
|
||||
let mut blocks = vec![];
|
||||
if let hir::Node::Block(block) = node
|
||||
&& let Some(expr) = block.expr
|
||||
&& let hir::ExprKind::Path(QPath::Resolved(_, Path { res, .. })) = expr.kind
|
||||
&& let Res::Local(local) = res
|
||||
&& let Node::Local(Local { init: Some(init), .. }) = self.tcx.parent_hir_node(*local)
|
||||
{
|
||||
fn collect_blocks<'hir>(expr: &hir::Expr<'hir>, blocks: &mut Vec<&hir::Block<'hir>>) {
|
||||
match expr.kind {
|
||||
// `blk1` and `blk2` must be have the same types, it will be reported before reaching here
|
||||
hir::ExprKind::If(_, blk1, Some(blk2)) => {
|
||||
collect_blocks(blk1, blocks);
|
||||
collect_blocks(blk2, blocks);
|
||||
}
|
||||
hir::ExprKind::Match(_, arms, _) => {
|
||||
// all arms must have same types
|
||||
for arm in arms.iter() {
|
||||
collect_blocks(arm.body, blocks);
|
||||
}
|
||||
}
|
||||
hir::ExprKind::Block(blk, _) => {
|
||||
blocks.push(blk);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
collect_blocks(init, &mut blocks);
|
||||
}
|
||||
|
||||
let expected_inner: Ty<'_> = expected.peel_refs();
|
||||
for block in blocks.iter() {
|
||||
self.consider_removing_semicolon(block, expected_inner, diag);
|
||||
}
|
||||
}
|
||||
|
||||
/// A common error is to add an extra semicolon:
|
||||
///
|
||||
/// ```compile_fail,E0308
|
||||
/// fn foo() -> usize {
|
||||
/// 22;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This routine checks if the final statement in a block is an
|
||||
/// expression with an explicit semicolon whose type is compatible
|
||||
/// with `expected_ty`. If so, it suggests removing the semicolon.
|
||||
pub fn consider_removing_semicolon(
|
||||
&self,
|
||||
blk: &'tcx hir::Block<'tcx>,
|
||||
expected_ty: Ty<'tcx>,
|
||||
diag: &mut Diag<'_>,
|
||||
) -> bool {
|
||||
if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
|
||||
if let StatementAsExpression::NeedsBoxing = boxed {
|
||||
diag.span_suggestion_verbose(
|
||||
span_semi,
|
||||
"consider removing this semicolon and boxing the expression",
|
||||
"",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
diag.span_suggestion_short(
|
||||
span_semi,
|
||||
"remove this semicolon to return this value",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn suggest_function_pointers(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
|
@ -135,16 +135,18 @@ pub struct FulfillmentError<'tcx> {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FulfillmentErrorCode<'tcx> {
|
||||
/// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
|
||||
/// Inherently impossible to fulfill; this trait is implemented if and only
|
||||
/// if it is already implemented.
|
||||
Cycle(Vec<PredicateObligation<'tcx>>),
|
||||
SelectionError(SelectionError<'tcx>),
|
||||
ProjectionError(MismatchedProjectionTypes<'tcx>),
|
||||
SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
|
||||
ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
|
||||
Ambiguity {
|
||||
/// Overflow reported from the new solver `-Znext-solver`, which will
|
||||
/// be reported as an regular error as opposed to a fatal error.
|
||||
overflow: bool,
|
||||
/// Overflow is only `Some(suggest_recursion_limit)` when using the next generation
|
||||
/// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by
|
||||
/// emitting a fatal error instead.
|
||||
overflow: Option<bool>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ConstEquateError(ref a, ref b) => {
|
||||
write!(f, "CodeConstEquateError({a:?}, {b:?})")
|
||||
}
|
||||
Ambiguity { overflow: false } => write!(f, "Ambiguity"),
|
||||
Ambiguity { overflow: true } => write!(f, "Overflow"),
|
||||
Ambiguity { overflow: None } => write!(f, "Ambiguity"),
|
||||
Ambiguity { overflow: Some(suggest_increasing_limit) } => {
|
||||
write!(f, "Overflow({suggest_increasing_limit})")
|
||||
}
|
||||
Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"),
|
||||
}
|
||||
}
|
||||
|
@ -3586,18 +3586,9 @@
|
||||
/// being validated. Usually these should be rejected as a hard error,
|
||||
/// but this lint was introduced to avoid breaking any existing
|
||||
/// crates which included them.
|
||||
///
|
||||
/// This is a [future-incompatible] lint to transition this to a hard
|
||||
/// error in the future. See [issue #82730] for more details.
|
||||
///
|
||||
/// [issue #82730]: https://github.com/rust-lang/rust/issues/82730
|
||||
pub INVALID_DOC_ATTRIBUTES,
|
||||
Warn,
|
||||
Deny,
|
||||
"detects invalid `#[doc(...)]` attributes",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||
reference: "issue #82730 <https://github.com/rust-lang/rust/issues/82730>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
@ -60,7 +60,6 @@ pub enum Certainty {
|
||||
|
||||
impl Certainty {
|
||||
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
|
||||
pub const OVERFLOW: Certainty = Certainty::Maybe(MaybeCause::Overflow);
|
||||
|
||||
/// Use this function to merge the certainty of multiple nested subgoals.
|
||||
///
|
||||
@ -79,16 +78,13 @@ pub fn unify_with(self, other: Certainty) -> Certainty {
|
||||
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
|
||||
(Certainty::Yes, Certainty::Maybe(_)) => other,
|
||||
(Certainty::Maybe(_), Certainty::Yes) => self,
|
||||
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
|
||||
Certainty::Maybe(MaybeCause::Ambiguity)
|
||||
}
|
||||
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow))
|
||||
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity))
|
||||
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
|
||||
Certainty::Maybe(MaybeCause::Overflow)
|
||||
}
|
||||
(Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
|
||||
Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
|
||||
}
|
||||
}
|
||||
|
||||
/// Why we failed to evaluate a goal.
|
||||
@ -99,7 +95,21 @@ pub enum MaybeCause {
|
||||
/// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
|
||||
Ambiguity,
|
||||
/// We gave up due to an overflow, most often by hitting the recursion limit.
|
||||
Overflow,
|
||||
Overflow { suggest_increasing_limit: bool },
|
||||
}
|
||||
|
||||
impl MaybeCause {
|
||||
fn unify_with(self, other: MaybeCause) -> MaybeCause {
|
||||
match (self, other) {
|
||||
(MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
|
||||
(MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
|
||||
(MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
|
||||
(
|
||||
MaybeCause::Overflow { suggest_increasing_limit: a },
|
||||
MaybeCause::Overflow { suggest_increasing_limit: b },
|
||||
) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||
|
@ -1097,21 +1097,18 @@ enum TestKind<'tcx> {
|
||||
variants: BitSet<VariantIdx>,
|
||||
},
|
||||
|
||||
/// Test what value an integer, `bool`, or `char` has.
|
||||
/// Test what value an integer or `char` has.
|
||||
SwitchInt {
|
||||
/// The type of the value that we're testing.
|
||||
switch_ty: Ty<'tcx>,
|
||||
/// The (ordered) set of values that we test for.
|
||||
///
|
||||
/// For integers and `char`s we create a branch to each of the values in
|
||||
/// `options`, as well as an "otherwise" branch for all other values, even
|
||||
/// in the (rare) case that `options` is exhaustive.
|
||||
///
|
||||
/// For `bool` we always generate two edges, one for `true` and one for
|
||||
/// `false`.
|
||||
/// We create a branch to each of the values in `options`, as well as an "otherwise" branch
|
||||
/// for all other values, even in the (rare) case that `options` is exhaustive.
|
||||
options: FxIndexMap<Const<'tcx>, u128>,
|
||||
},
|
||||
|
||||
/// Test what value a `bool` has.
|
||||
If,
|
||||
|
||||
/// Test for equality with value, possibly after an unsizing coercion to
|
||||
/// `ty`,
|
||||
Eq {
|
||||
@ -1617,7 +1614,7 @@ fn pick_test(
|
||||
// a test like SwitchInt, we may want to add cases based on the candidates that are
|
||||
// available
|
||||
match test.kind {
|
||||
TestKind::SwitchInt { switch_ty: _, ref mut options } => {
|
||||
TestKind::SwitchInt { ref mut options } => {
|
||||
for candidate in candidates.iter() {
|
||||
if !self.add_cases_to_switch(&match_place, candidate, options) {
|
||||
break;
|
||||
|
@ -34,12 +34,12 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
|
||||
TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
|
||||
}
|
||||
|
||||
TestCase::Constant { .. } if match_pair.pattern.ty.is_bool() => TestKind::If,
|
||||
|
||||
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
|
||||
// For integers, we use a `SwitchInt` match, which allows
|
||||
// us to handle more cases.
|
||||
TestKind::SwitchInt {
|
||||
switch_ty: match_pair.pattern.ty,
|
||||
|
||||
// these maps are empty to start; cases are
|
||||
// added below in add_cases_to_switch
|
||||
options: Default::default(),
|
||||
@ -182,34 +182,29 @@ pub(super) fn perform_test(
|
||||
);
|
||||
}
|
||||
|
||||
TestKind::SwitchInt { switch_ty, ref options } => {
|
||||
let terminator = if *switch_ty.kind() == ty::Bool {
|
||||
assert!(!options.is_empty() && options.len() <= 2);
|
||||
let [first_bb, second_bb] = *target_blocks else {
|
||||
bug!("`TestKind::SwitchInt` on `bool` should have two targets")
|
||||
};
|
||||
let (true_bb, false_bb) = match options[0] {
|
||||
1 => (first_bb, second_bb),
|
||||
0 => (second_bb, first_bb),
|
||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v),
|
||||
};
|
||||
TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb)
|
||||
} else {
|
||||
// The switch may be inexhaustive so we have a catch all block
|
||||
debug_assert_eq!(options.len() + 1, target_blocks.len());
|
||||
let otherwise_block = *target_blocks.last().unwrap();
|
||||
let switch_targets = SwitchTargets::new(
|
||||
options.values().copied().zip(target_blocks),
|
||||
otherwise_block,
|
||||
);
|
||||
TerminatorKind::SwitchInt {
|
||||
discr: Operand::Copy(place),
|
||||
targets: switch_targets,
|
||||
}
|
||||
TestKind::SwitchInt { ref options } => {
|
||||
// The switch may be inexhaustive so we have a catch-all block
|
||||
debug_assert_eq!(options.len() + 1, target_blocks.len());
|
||||
let otherwise_block = *target_blocks.last().unwrap();
|
||||
let switch_targets = SwitchTargets::new(
|
||||
options.values().copied().zip(target_blocks),
|
||||
otherwise_block,
|
||||
);
|
||||
let terminator = TerminatorKind::SwitchInt {
|
||||
discr: Operand::Copy(place),
|
||||
targets: switch_targets,
|
||||
};
|
||||
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
||||
}
|
||||
|
||||
TestKind::If => {
|
||||
let [false_bb, true_bb] = *target_blocks else {
|
||||
bug!("`TestKind::If` should have two targets")
|
||||
};
|
||||
let terminator = TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb);
|
||||
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
||||
}
|
||||
|
||||
TestKind::Eq { value, ty } => {
|
||||
let tcx = self.tcx;
|
||||
let [success_block, fail_block] = *target_blocks else {
|
||||
@ -583,24 +578,20 @@ pub(super) fn sort_candidate<'pat>(
|
||||
fully_matched = true;
|
||||
Some(variant_index.as_usize())
|
||||
}
|
||||
(&TestKind::Switch { .. }, _) => {
|
||||
fully_matched = false;
|
||||
None
|
||||
}
|
||||
|
||||
// If we are performing a switch over integers, then this informs integer
|
||||
// equality, but nothing else.
|
||||
//
|
||||
// FIXME(#29623) we could use PatKind::Range to rule
|
||||
// things out here, in some cases.
|
||||
(TestKind::SwitchInt { switch_ty: _, options }, TestCase::Constant { value })
|
||||
(TestKind::SwitchInt { options }, TestCase::Constant { value })
|
||||
if is_switch_ty(match_pair.pattern.ty) =>
|
||||
{
|
||||
fully_matched = true;
|
||||
let index = options.get_index_of(value).unwrap();
|
||||
Some(index)
|
||||
}
|
||||
(TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => {
|
||||
(TestKind::SwitchInt { options }, TestCase::Range(range)) => {
|
||||
fully_matched = false;
|
||||
let not_contained =
|
||||
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
|
||||
@ -611,7 +602,15 @@ pub(super) fn sort_candidate<'pat>(
|
||||
options.len()
|
||||
})
|
||||
}
|
||||
(&TestKind::SwitchInt { .. }, _) => {
|
||||
|
||||
(&TestKind::If, TestCase::Constant { value }) => {
|
||||
fully_matched = true;
|
||||
let value = value.try_eval_bool(self.tcx, self.param_env).unwrap_or_else(|| {
|
||||
span_bug!(test.span, "expected boolean value but got {value:?}")
|
||||
});
|
||||
Some(value as usize)
|
||||
}
|
||||
(&TestKind::If, _) => {
|
||||
fully_matched = false;
|
||||
None
|
||||
}
|
||||
@ -703,34 +702,25 @@ pub(super) fn sort_candidate<'pat>(
|
||||
None
|
||||
}
|
||||
}
|
||||
(&TestKind::Range { .. }, _) => {
|
||||
fully_matched = false;
|
||||
None
|
||||
|
||||
// FIXME(#29623): return `Some(1)` when the values are different.
|
||||
(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val })
|
||||
if test_val == case_val =>
|
||||
{
|
||||
fully_matched = true;
|
||||
Some(0)
|
||||
}
|
||||
|
||||
(&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => {
|
||||
// The call to `self.test(&match_pair)` below is not actually used to generate any
|
||||
// MIR. Instead, we just want to compare with `test` (the parameter of the method)
|
||||
// to see if it is the same.
|
||||
//
|
||||
// However, at this point we can still encounter or-patterns that were extracted
|
||||
// from previous calls to `sort_candidate`, so we need to manually address that
|
||||
// case to avoid panicking in `self.test()`.
|
||||
if let TestCase::Or { .. } = &match_pair.test_case {
|
||||
return None;
|
||||
}
|
||||
|
||||
// These are all binary tests.
|
||||
//
|
||||
// FIXME(#29623) we can be more clever here
|
||||
let pattern_test = self.test(match_pair);
|
||||
if pattern_test.kind == test.kind {
|
||||
fully_matched = true;
|
||||
Some(0)
|
||||
} else {
|
||||
fully_matched = false;
|
||||
None
|
||||
}
|
||||
(
|
||||
TestKind::Switch { .. }
|
||||
| TestKind::SwitchInt { .. }
|
||||
| TestKind::Len { .. }
|
||||
| TestKind::Range { .. }
|
||||
| TestKind::Eq { .. },
|
||||
_,
|
||||
) => {
|
||||
fully_matched = false;
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
@ -763,7 +753,7 @@ fn values_not_contained_in_range(
|
||||
impl Test<'_> {
|
||||
pub(super) fn targets(&self) -> usize {
|
||||
match self.kind {
|
||||
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => 2,
|
||||
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } | TestKind::If => 2,
|
||||
TestKind::Switch { adt_def, .. } => {
|
||||
// While the switch that we generate doesn't test for all
|
||||
// variants, we have a target for each variant and the
|
||||
@ -771,21 +761,13 @@ pub(super) fn targets(&self) -> usize {
|
||||
// specified have the same block.
|
||||
adt_def.variants().len() + 1
|
||||
}
|
||||
TestKind::SwitchInt { switch_ty, ref options, .. } => {
|
||||
if switch_ty.is_bool() {
|
||||
// `bool` is special cased in `perform_test` to always
|
||||
// branch to two blocks.
|
||||
2
|
||||
} else {
|
||||
options.len() + 1
|
||||
}
|
||||
}
|
||||
TestKind::SwitchInt { ref options } => options.len() + 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_switch_ty(ty: Ty<'_>) -> bool {
|
||||
ty.is_integral() || ty.is_char() || ty.is_bool()
|
||||
ty.is_integral() || ty.is_char()
|
||||
}
|
||||
|
||||
fn trait_method<'tcx>(
|
||||
|
@ -6,11 +6,13 @@
|
||||
use rustc_middle::ty;
|
||||
use rustc_target::abi::call::Conv;
|
||||
use stable_mir::abi::{
|
||||
ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding,
|
||||
TyAndLayout, ValueAbi, VariantsShape,
|
||||
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
|
||||
LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
|
||||
WrappingRange,
|
||||
};
|
||||
use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx};
|
||||
use stable_mir::{opaque, Opaque};
|
||||
use stable_mir::opaque;
|
||||
use stable_mir::target::MachineSize as Size;
|
||||
use stable_mir::ty::{Align, IndexedVal, VariantIdx};
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
|
||||
type T = VariantIdx;
|
||||
@ -220,7 +222,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Size {
|
||||
type T = Size;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||
self.bytes_usize()
|
||||
Size::from_bits(self.bits_usize())
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,9 +235,62 @@ fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
|
||||
type T = Opaque;
|
||||
type T = Scalar;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||
opaque(self)
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::Scalar::Initialized { value, valid_range } => Scalar::Initialized {
|
||||
value: value.stable(tables),
|
||||
valid_range: valid_range.stable(tables),
|
||||
},
|
||||
rustc_abi::Scalar::Union { value } => Scalar::Union { value: value.stable(tables) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Primitive {
|
||||
type T = Primitive;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::Primitive::Int(length, signed) => {
|
||||
Primitive::Int { length: length.stable(tables), signed: *signed }
|
||||
}
|
||||
rustc_abi::Primitive::F16 => Primitive::Float { length: FloatLength::F16 },
|
||||
rustc_abi::Primitive::F32 => Primitive::Float { length: FloatLength::F32 },
|
||||
rustc_abi::Primitive::F64 => Primitive::Float { length: FloatLength::F64 },
|
||||
rustc_abi::Primitive::F128 => Primitive::Float { length: FloatLength::F128 },
|
||||
rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::AddressSpace {
|
||||
type T = AddressSpace;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||
AddressSpace(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::Integer {
|
||||
type T = IntegerLength;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||
match self {
|
||||
rustc_abi::Integer::I8 => IntegerLength::I8,
|
||||
rustc_abi::Integer::I16 => IntegerLength::I16,
|
||||
rustc_abi::Integer::I32 => IntegerLength::I32,
|
||||
rustc_abi::Integer::I64 => IntegerLength::I64,
|
||||
rustc_abi::Integer::I128 => IntegerLength::I128,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
|
||||
type T = WrappingRange;
|
||||
|
||||
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||
WrappingRange { start: self.start, end: self.end }
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,13 @@ pub(super) fn compute_alias_relate_goal(
|
||||
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
||||
|
||||
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
|
||||
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
|
||||
return self
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
|
||||
};
|
||||
|
||||
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
|
||||
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
|
||||
return self
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
|
||||
};
|
||||
|
||||
let variance = match direction {
|
||||
|
@ -7,6 +7,7 @@
|
||||
BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::MaybeCause;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::infer::canonical::CanonicalVarInfos;
|
||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
@ -29,7 +30,7 @@
|
||||
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
use super::{search_graph, GoalEvaluationKind};
|
||||
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
|
||||
use super::{search_graph::SearchGraph, Goal};
|
||||
use super::{GoalSource, SolverMode};
|
||||
pub use select::InferCtxtSelectExt;
|
||||
@ -154,10 +155,6 @@ pub(super) fn solver_mode(&self) -> SolverMode {
|
||||
self.search_graph.solver_mode()
|
||||
}
|
||||
|
||||
pub(super) fn local_overflow_limit(&self) -> usize {
|
||||
self.search_graph.local_overflow_limit()
|
||||
}
|
||||
|
||||
/// Creates a root evaluation context and search graph. This should only be
|
||||
/// used from outside of any evaluation, and other methods should be preferred
|
||||
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
|
||||
@ -167,7 +164,7 @@ fn enter_root<R>(
|
||||
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
|
||||
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
|
||||
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
|
||||
let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode);
|
||||
let mut search_graph = search_graph::SearchGraph::new(mode);
|
||||
|
||||
let mut ecx = EvalCtxt {
|
||||
search_graph: &mut search_graph,
|
||||
@ -388,16 +385,18 @@ fn instantiate_response_discarding_overflow(
|
||||
&& source != GoalSource::ImplWhereBound
|
||||
};
|
||||
|
||||
if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
|
||||
(Certainty::OVERFLOW, false)
|
||||
} else {
|
||||
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|
||||
|| !response.value.external_constraints.opaque_types.is_empty();
|
||||
|
||||
let certainty =
|
||||
self.instantiate_and_apply_query_response(param_env, original_values, response);
|
||||
(certainty, has_changed)
|
||||
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty
|
||||
&& !keep_overflow_constraints()
|
||||
{
|
||||
return (response.value.certainty, false);
|
||||
}
|
||||
|
||||
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|
||||
|| !response.value.external_constraints.opaque_types.is_empty();
|
||||
|
||||
let certainty =
|
||||
self.instantiate_and_apply_query_response(param_env, original_values, response);
|
||||
(certainty, has_changed)
|
||||
}
|
||||
|
||||
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
||||
@ -466,8 +465,8 @@ pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolutio
|
||||
let inspect = self.inspect.new_evaluate_added_goals();
|
||||
let inspect = core::mem::replace(&mut self.inspect, inspect);
|
||||
|
||||
let mut response = Ok(Certainty::OVERFLOW);
|
||||
for _ in 0..self.local_overflow_limit() {
|
||||
let mut response = Ok(Certainty::overflow(false));
|
||||
for _ in 0..FIXPOINT_STEP_LIMIT {
|
||||
// FIXME: This match is a bit ugly, it might be nice to change the inspect
|
||||
// stuff to use a closure instead. which should hopefully simplify this a bit.
|
||||
match self.evaluate_added_goals_step() {
|
||||
|
@ -24,7 +24,7 @@
|
||||
/// It is also likely that we want to use slightly different datastructures
|
||||
/// here as this will have to deal with far more root goals than `evaluate_all`.
|
||||
pub struct FulfillmentCtxt<'tcx> {
|
||||
obligations: Vec<PredicateObligation<'tcx>>,
|
||||
obligations: ObligationStorage<'tcx>,
|
||||
|
||||
/// The snapshot in which this context was created. Using the context
|
||||
/// outside of this snapshot leads to subtle bugs if the snapshot
|
||||
@ -33,6 +33,57 @@ pub struct FulfillmentCtxt<'tcx> {
|
||||
usable_in_snapshot: usize,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ObligationStorage<'tcx> {
|
||||
/// Obligations which resulted in an overflow in fulfillment itself.
|
||||
///
|
||||
/// We cannot eagerly return these as error so we instead store them here
|
||||
/// to avoid recomputing them each time `select_where_possible` is called.
|
||||
/// This also allows us to return the correct `FulfillmentError` for them.
|
||||
overflowed: Vec<PredicateObligation<'tcx>>,
|
||||
pending: Vec<PredicateObligation<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationStorage<'tcx> {
|
||||
fn register(&mut self, obligation: PredicateObligation<'tcx>) {
|
||||
self.pending.push(obligation);
|
||||
}
|
||||
|
||||
fn clone_pending(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||
let mut obligations = self.pending.clone();
|
||||
obligations.extend(self.overflowed.iter().cloned());
|
||||
obligations
|
||||
}
|
||||
|
||||
fn take_pending(&mut self) -> Vec<PredicateObligation<'tcx>> {
|
||||
let mut obligations = mem::take(&mut self.pending);
|
||||
obligations.extend(self.overflowed.drain(..));
|
||||
obligations
|
||||
}
|
||||
|
||||
fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> {
|
||||
mem::take(&mut self.pending).into_iter()
|
||||
}
|
||||
|
||||
fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
|
||||
infcx.probe(|_| {
|
||||
// IMPORTANT: we must not use solve any inference variables in the obligations
|
||||
// as this is all happening inside of a probe. We use a probe to make sure
|
||||
// we get all obligations involved in the overflow. We pretty much check: if
|
||||
// we were to do another step of `select_where_possible`, which goals would
|
||||
// change.
|
||||
self.overflowed.extend(self.pending.extract_if(|o| {
|
||||
let goal = o.clone().into();
|
||||
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::Never).0;
|
||||
match result {
|
||||
Ok((has_changed, _)) => has_changed,
|
||||
_ => false,
|
||||
}
|
||||
}));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FulfillmentCtxt<'tcx> {
|
||||
pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
|
||||
assert!(
|
||||
@ -40,7 +91,10 @@ pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
|
||||
"new trait solver fulfillment context created when \
|
||||
infcx is set up for old trait solver"
|
||||
);
|
||||
FulfillmentCtxt { obligations: Vec::new(), usable_in_snapshot: infcx.num_open_snapshots() }
|
||||
FulfillmentCtxt {
|
||||
obligations: Default::default(),
|
||||
usable_in_snapshot: infcx.num_open_snapshots(),
|
||||
}
|
||||
}
|
||||
|
||||
fn inspect_evaluated_obligation(
|
||||
@ -67,40 +121,24 @@ fn register_predicate_obligation(
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) {
|
||||
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
|
||||
self.obligations.push(obligation);
|
||||
self.obligations.register(obligation);
|
||||
}
|
||||
|
||||
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.obligations
|
||||
let mut errors: Vec<_> = self
|
||||
.obligations
|
||||
.pending
|
||||
.drain(..)
|
||||
.map(|obligation| {
|
||||
let code = infcx.probe(|_| {
|
||||
match infcx
|
||||
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled)
|
||||
.0
|
||||
{
|
||||
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
|
||||
FulfillmentErrorCode::Ambiguity { overflow: false }
|
||||
}
|
||||
Ok((_, Certainty::Maybe(MaybeCause::Overflow))) => {
|
||||
FulfillmentErrorCode::Ambiguity { overflow: true }
|
||||
}
|
||||
Ok((_, Certainty::Yes)) => {
|
||||
bug!("did not expect successful goal when collecting ambiguity errors")
|
||||
}
|
||||
Err(_) => {
|
||||
bug!("did not expect selection error when collecting ambiguity errors")
|
||||
}
|
||||
}
|
||||
});
|
||||
.map(|obligation| fulfillment_error_for_stalled(infcx, obligation))
|
||||
.collect();
|
||||
|
||||
FulfillmentError {
|
||||
obligation: obligation.clone(),
|
||||
code,
|
||||
root_obligation: obligation,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError {
|
||||
root_obligation: obligation.clone(),
|
||||
code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
|
||||
obligation,
|
||||
}));
|
||||
|
||||
errors
|
||||
}
|
||||
|
||||
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||
@ -108,79 +146,27 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
|
||||
let mut errors = Vec::new();
|
||||
for i in 0.. {
|
||||
if !infcx.tcx.recursion_limit().value_within_limit(i) {
|
||||
// Only return true errors that we have accumulated while processing;
|
||||
// keep ambiguities around, *including overflows*, because they shouldn't
|
||||
// be considered true errors.
|
||||
self.obligations.on_fulfillment_overflow(infcx);
|
||||
// Only return true errors that we have accumulated while processing.
|
||||
return errors;
|
||||
}
|
||||
|
||||
let mut has_changed = false;
|
||||
for obligation in mem::take(&mut self.obligations) {
|
||||
for obligation in self.obligations.unstalled_for_select() {
|
||||
let goal = obligation.clone().into();
|
||||
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0;
|
||||
self.inspect_evaluated_obligation(infcx, &obligation, &result);
|
||||
let (changed, certainty) = match result {
|
||||
Ok(result) => result,
|
||||
Err(NoSolution) => {
|
||||
errors.push(FulfillmentError {
|
||||
obligation: obligation.clone(),
|
||||
code: match goal.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
|
||||
FulfillmentErrorCode::ProjectionError(
|
||||
// FIXME: This could be a `Sorts` if the term is a type
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::NormalizesTo(..) => {
|
||||
FulfillmentErrorCode::ProjectionError(
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(_, _, _) => {
|
||||
FulfillmentErrorCode::ProjectionError(
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::Subtype(pred) => {
|
||||
let (a, b) = infcx.enter_forall_and_leak_universe(
|
||||
goal.predicate.kind().rebind((pred.a, pred.b)),
|
||||
);
|
||||
let expected_found = ExpectedFound::new(true, a, b);
|
||||
FulfillmentErrorCode::SubtypeError(
|
||||
expected_found,
|
||||
TypeError::Sorts(expected_found),
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::Coerce(pred) => {
|
||||
let (a, b) = infcx.enter_forall_and_leak_universe(
|
||||
goal.predicate.kind().rebind((pred.a, pred.b)),
|
||||
);
|
||||
let expected_found = ExpectedFound::new(false, a, b);
|
||||
FulfillmentErrorCode::SubtypeError(
|
||||
expected_found,
|
||||
TypeError::Sorts(expected_found),
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::Clause(_)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::Ambiguous => {
|
||||
FulfillmentErrorCode::SelectionError(
|
||||
SelectionError::Unimplemented,
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(..) => {
|
||||
bug!("unexpected goal: {goal:?}")
|
||||
}
|
||||
},
|
||||
root_obligation: obligation,
|
||||
});
|
||||
errors.push(fulfillment_error_for_no_solution(infcx, obligation));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
has_changed |= changed;
|
||||
match certainty {
|
||||
Certainty::Yes => {}
|
||||
Certainty::Maybe(_) => self.obligations.push(obligation),
|
||||
Certainty::Maybe(_) => self.obligations.register(obligation),
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,13 +179,84 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
|
||||
}
|
||||
|
||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||
self.obligations.clone()
|
||||
self.obligations.clone_pending()
|
||||
}
|
||||
|
||||
fn drain_unstalled_obligations(
|
||||
&mut self,
|
||||
_: &InferCtxt<'tcx>,
|
||||
) -> Vec<PredicateObligation<'tcx>> {
|
||||
std::mem::take(&mut self.obligations)
|
||||
self.obligations.take_pending()
|
||||
}
|
||||
}
|
||||
|
||||
fn fulfillment_error_for_no_solution<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) -> FulfillmentError<'tcx> {
|
||||
let code = match obligation.predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
|
||||
FulfillmentErrorCode::ProjectionError(
|
||||
// FIXME: This could be a `Sorts` if the term is a type
|
||||
MismatchedProjectionTypes { err: TypeError::Mismatch },
|
||||
)
|
||||
}
|
||||
ty::PredicateKind::NormalizesTo(..) => {
|
||||
FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
|
||||
err: TypeError::Mismatch,
|
||||
})
|
||||
}
|
||||
ty::PredicateKind::AliasRelate(_, _, _) => {
|
||||
FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
|
||||
err: TypeError::Mismatch,
|
||||
})
|
||||
}
|
||||
ty::PredicateKind::Subtype(pred) => {
|
||||
let (a, b) = infcx.enter_forall_and_leak_universe(
|
||||
obligation.predicate.kind().rebind((pred.a, pred.b)),
|
||||
);
|
||||
let expected_found = ExpectedFound::new(true, a, b);
|
||||
FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
|
||||
}
|
||||
ty::PredicateKind::Coerce(pred) => {
|
||||
let (a, b) = infcx.enter_forall_and_leak_universe(
|
||||
obligation.predicate.kind().rebind((pred.a, pred.b)),
|
||||
);
|
||||
let expected_found = ExpectedFound::new(false, a, b);
|
||||
FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
|
||||
}
|
||||
ty::PredicateKind::Clause(_)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::Ambiguous => {
|
||||
FulfillmentErrorCode::SelectionError(SelectionError::Unimplemented)
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(..) => {
|
||||
bug!("unexpected goal: {obligation:?}")
|
||||
}
|
||||
};
|
||||
FulfillmentError { root_obligation: obligation.clone(), code, obligation }
|
||||
}
|
||||
|
||||
fn fulfillment_error_for_stalled<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
) -> FulfillmentError<'tcx> {
|
||||
let code = infcx.probe(|_| {
|
||||
match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 {
|
||||
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
|
||||
FulfillmentErrorCode::Ambiguity { overflow: None }
|
||||
}
|
||||
Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => {
|
||||
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }
|
||||
}
|
||||
Ok((_, Certainty::Yes)) => {
|
||||
bug!("did not expect successful goal when collecting ambiguity errors")
|
||||
}
|
||||
Err(_) => {
|
||||
bug!("did not expect selection error when collecting ambiguity errors")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
FulfillmentError { obligation: obligation.clone(), code, root_obligation: obligation }
|
||||
}
|
||||
|
@ -42,6 +42,17 @@
|
||||
pub(crate) use normalize::deeply_normalize_for_diagnostics;
|
||||
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
|
||||
|
||||
/// How many fixpoint iterations we should attempt inside of the solver before bailing
|
||||
/// with overflow.
|
||||
///
|
||||
/// We previously used `tcx.recursion_limit().0.checked_ilog2().unwrap_or(0)` for this.
|
||||
/// However, it feels unlikely that uncreasing the recursion limit by a power of two
|
||||
/// to get one more itereation is every useful or desirable. We now instead used a constant
|
||||
/// here. If there ever ends up some use-cases where a bigger number of fixpoint iterations
|
||||
/// is required, we can add a new attribute for that or revert this to be dependant on the
|
||||
/// recursion limit again. However, this feels very unlikely.
|
||||
const FIXPOINT_STEP_LIMIT: usize = 8;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum SolverMode {
|
||||
/// Ordinary trait solving, using everywhere except for coherence.
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::solve::FIXPOINT_STEP_LIMIT;
|
||||
|
||||
use super::inspect;
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
use super::SolverMode;
|
||||
@ -99,7 +101,6 @@ fn is_empty(&self) -> bool {
|
||||
|
||||
pub(super) struct SearchGraph<'tcx> {
|
||||
mode: SolverMode,
|
||||
local_overflow_limit: usize,
|
||||
/// The stack of goals currently being computed.
|
||||
///
|
||||
/// An element is *deeper* in the stack if its index is *lower*.
|
||||
@ -116,10 +117,9 @@ pub(super) struct SearchGraph<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> SearchGraph<'tcx> {
|
||||
pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
|
||||
pub(super) fn new(mode: SolverMode) -> SearchGraph<'tcx> {
|
||||
Self {
|
||||
mode,
|
||||
local_overflow_limit: tcx.recursion_limit().0.checked_ilog2().unwrap_or(0) as usize,
|
||||
stack: Default::default(),
|
||||
provisional_cache: Default::default(),
|
||||
cycle_participants: Default::default(),
|
||||
@ -130,10 +130,6 @@ pub(super) fn solver_mode(&self) -> SolverMode {
|
||||
self.mode
|
||||
}
|
||||
|
||||
pub(super) fn local_overflow_limit(&self) -> usize {
|
||||
self.local_overflow_limit
|
||||
}
|
||||
|
||||
/// Update the stack and reached depths on cache hits.
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
|
||||
@ -277,7 +273,7 @@ pub(super) fn with_new_goal(
|
||||
}
|
||||
|
||||
inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow);
|
||||
return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
|
||||
return Self::response_no_constraints(tcx, input, Certainty::overflow(true));
|
||||
};
|
||||
|
||||
// Try to fetch the goal from the global cache.
|
||||
@ -370,7 +366,7 @@ pub(super) fn with_new_goal(
|
||||
} else if is_coinductive_cycle {
|
||||
Self::response_no_constraints(tcx, input, Certainty::Yes)
|
||||
} else {
|
||||
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW)
|
||||
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
|
||||
};
|
||||
} else {
|
||||
// No entry, we push this goal on the stack and try to prove it.
|
||||
@ -398,7 +394,7 @@ pub(super) fn with_new_goal(
|
||||
// of this we continuously recompute the cycle until the result
|
||||
// of the previous iteration is equal to the final result, at which
|
||||
// point we are done.
|
||||
for _ in 0..self.local_overflow_limit() {
|
||||
for _ in 0..FIXPOINT_STEP_LIMIT {
|
||||
let result = prove_goal(self, inspect);
|
||||
let stack_entry = self.pop_stack();
|
||||
debug_assert_eq!(stack_entry.input, input);
|
||||
@ -431,7 +427,8 @@ pub(super) fn with_new_goal(
|
||||
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
|
||||
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
|
||||
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
|
||||
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW) == result
|
||||
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
|
||||
== result
|
||||
} else {
|
||||
false
|
||||
};
|
||||
@ -452,7 +449,7 @@ pub(super) fn with_new_goal(
|
||||
debug!("canonical cycle overflow");
|
||||
let current_entry = self.pop_stack();
|
||||
debug_assert!(current_entry.has_been_used.is_empty());
|
||||
let result = Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
|
||||
let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false));
|
||||
(current_entry, result)
|
||||
});
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{util, TraitEngine, TraitEngineExt};
|
||||
use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineExt};
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
|
||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||
@ -35,6 +35,8 @@
|
||||
use std::fmt::Debug;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use super::error_reporting::suggest_new_overflow_limit;
|
||||
|
||||
/// Whether we do the orphan check relative to this crate or
|
||||
/// to some remote crate.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -56,6 +58,9 @@ pub struct OverlapResult<'tcx> {
|
||||
/// `true` if the overlap might've been permitted before the shift
|
||||
/// to universes.
|
||||
pub involves_placeholder: bool,
|
||||
|
||||
/// Used in the new solver to suggest increasing the recursion limit.
|
||||
pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
|
||||
@ -65,6 +70,18 @@ pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn suggest_increasing_recursion_limit<'tcx, G: EmissionGuarantee>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diag<'_, G>,
|
||||
overflowing_predicates: &[ty::Predicate<'tcx>],
|
||||
) {
|
||||
for pred in overflowing_predicates {
|
||||
err.note(format!("overflow evaluating the requirement `{}`", pred));
|
||||
}
|
||||
|
||||
suggest_new_overflow_limit(tcx, err);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum TrackAmbiguityCauses {
|
||||
Yes,
|
||||
@ -221,11 +238,13 @@ fn overlap<'tcx>(
|
||||
),
|
||||
);
|
||||
|
||||
let mut overflowing_predicates = Vec::new();
|
||||
if overlap_mode.use_implicit_negative() {
|
||||
if let Some(_failing_obligation) =
|
||||
impl_intersection_has_impossible_obligation(selcx, &obligations)
|
||||
{
|
||||
return None;
|
||||
match impl_intersection_has_impossible_obligation(selcx, &obligations) {
|
||||
IntersectionHasImpossibleObligations::Yes => return None,
|
||||
IntersectionHasImpossibleObligations::No { overflowing_predicates: p } => {
|
||||
overflowing_predicates = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +280,12 @@ fn overlap<'tcx>(
|
||||
impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
|
||||
}
|
||||
|
||||
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
|
||||
Some(OverlapResult {
|
||||
impl_header,
|
||||
intercrate_ambiguity_causes,
|
||||
involves_placeholder,
|
||||
overflowing_predicates,
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(infcx), ret)]
|
||||
@ -287,6 +311,19 @@ fn equate_impl_headers<'tcx>(
|
||||
result.map(|infer_ok| infer_ok.obligations).ok()
|
||||
}
|
||||
|
||||
/// The result of [fn impl_intersection_has_impossible_obligation].
|
||||
enum IntersectionHasImpossibleObligations<'tcx> {
|
||||
Yes,
|
||||
No {
|
||||
/// With `-Znext-solver=coherence`, some obligations may
|
||||
/// fail if only the user increased the recursion limit.
|
||||
///
|
||||
/// We return those obligations here and mention them in the
|
||||
/// error message.
|
||||
overflowing_predicates: Vec<ty::Predicate<'tcx>>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Check if both impls can be satisfied by a common type by considering whether
|
||||
/// any of either impl's obligations is not known to hold.
|
||||
///
|
||||
@ -308,7 +345,7 @@ fn equate_impl_headers<'tcx>(
|
||||
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligations: &'a [PredicateObligation<'tcx>],
|
||||
) -> Option<PredicateObligation<'tcx>> {
|
||||
) -> IntersectionHasImpossibleObligations<'tcx> {
|
||||
let infcx = selcx.infcx;
|
||||
|
||||
if infcx.next_trait_solver() {
|
||||
@ -317,28 +354,42 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
|
||||
|
||||
// We only care about the obligations that are *definitely* true errors.
|
||||
// Ambiguities do not prove the disjointness of two impls.
|
||||
let mut errors = fulfill_cx.select_where_possible(infcx);
|
||||
errors.pop().map(|err| err.obligation)
|
||||
let errors = fulfill_cx.select_where_possible(infcx);
|
||||
if errors.is_empty() {
|
||||
let overflow_errors = fulfill_cx.collect_remaining_errors(infcx);
|
||||
let overflowing_predicates = overflow_errors
|
||||
.into_iter()
|
||||
.filter(|e| match e.code {
|
||||
FulfillmentErrorCode::Ambiguity { overflow: Some(true) } => true,
|
||||
_ => false,
|
||||
})
|
||||
.map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
|
||||
.collect();
|
||||
IntersectionHasImpossibleObligations::No { overflowing_predicates }
|
||||
} else {
|
||||
IntersectionHasImpossibleObligations::Yes
|
||||
}
|
||||
} else {
|
||||
obligations
|
||||
.iter()
|
||||
.find(|obligation| {
|
||||
// We use `evaluate_root_obligation` to correctly track intercrate
|
||||
// ambiguity clauses. We cannot use this in the new solver.
|
||||
let evaluation_result = selcx.evaluate_root_obligation(obligation);
|
||||
for obligation in obligations {
|
||||
// We use `evaluate_root_obligation` to correctly track intercrate
|
||||
// ambiguity clauses.
|
||||
let evaluation_result = selcx.evaluate_root_obligation(obligation);
|
||||
|
||||
match evaluation_result {
|
||||
Ok(result) => !result.may_apply(),
|
||||
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
|
||||
// since there can be instantiations of this goal that don't overflow and result in
|
||||
// success. This isn't much of a problem in the old solver, since we treat overflow
|
||||
// fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
|
||||
// but in the new solver, this is very important for correctness, since overflow
|
||||
// *must* be treated as ambiguity for completeness.
|
||||
Err(_overflow) => false,
|
||||
match evaluation_result {
|
||||
Ok(result) => {
|
||||
if !result.may_apply() {
|
||||
return IntersectionHasImpossibleObligations::Yes;
|
||||
}
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
|
||||
// since there can be instantiations of this goal that don't overflow and result in
|
||||
// success. While this isn't much of a problem in the old solver, since we treat overflow
|
||||
// fatally, this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>.
|
||||
Err(_overflow) => {}
|
||||
}
|
||||
}
|
||||
|
||||
IntersectionHasImpossibleObligations::No { overflowing_predicates: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,9 @@
|
||||
SelectionError, SignatureMismatch, TraitNotObjectSafe,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_errors::{
|
||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
|
||||
MultiSpan, StashKey, StringPart,
|
||||
};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
|
||||
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
@ -62,6 +61,22 @@ pub enum OverflowCause<'tcx> {
|
||||
TraitSolver(ty::Predicate<'tcx>),
|
||||
}
|
||||
|
||||
pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diag<'_, G>,
|
||||
) {
|
||||
let suggested_limit = match tcx.recursion_limit() {
|
||||
Limit(0) => Limit(2),
|
||||
limit => limit * 2,
|
||||
};
|
||||
err.help(format!(
|
||||
"consider increasing the recursion limit by adding a \
|
||||
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
|
||||
suggested_limit,
|
||||
tcx.crate_name(LOCAL_CRATE),
|
||||
));
|
||||
}
|
||||
|
||||
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
|
||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
fn report_fulfillment_errors(
|
||||
@ -263,7 +278,7 @@ fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
|
||||
};
|
||||
|
||||
if suggest_increasing_limit {
|
||||
self.suggest_new_overflow_limit(&mut err);
|
||||
suggest_new_overflow_limit(self.tcx, &mut err);
|
||||
}
|
||||
|
||||
err
|
||||
@ -303,19 +318,6 @@ fn report_overflow_obligation<T>(
|
||||
);
|
||||
}
|
||||
|
||||
fn suggest_new_overflow_limit(&self, err: &mut Diag<'_>) {
|
||||
let suggested_limit = match self.tcx.recursion_limit() {
|
||||
Limit(0) => Limit(2),
|
||||
limit => limit * 2,
|
||||
};
|
||||
err.help(format!(
|
||||
"consider increasing the recursion limit by adding a \
|
||||
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
|
||||
suggested_limit,
|
||||
self.tcx.crate_name(LOCAL_CRATE),
|
||||
));
|
||||
}
|
||||
|
||||
/// Reports that a cycle was detected which led to overflow and halts
|
||||
/// compilation. This is equivalent to `report_overflow_obligation` except
|
||||
/// that we can give a more helpful error message (and, in particular,
|
||||
@ -335,12 +337,16 @@ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>])
|
||||
);
|
||||
}
|
||||
|
||||
fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
|
||||
fn report_overflow_no_abort(
|
||||
&self,
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
suggest_increasing_limit: bool,
|
||||
) -> ErrorGuaranteed {
|
||||
let obligation = self.resolve_vars_if_possible(obligation);
|
||||
let mut err = self.build_overflow_error(
|
||||
OverflowCause::TraitSolver(obligation.predicate),
|
||||
obligation.cause.span,
|
||||
true,
|
||||
suggest_increasing_limit,
|
||||
);
|
||||
self.note_obligation_cause(&mut err, &obligation);
|
||||
self.point_at_returns_when_relevant(&mut err, &obligation);
|
||||
@ -1422,11 +1428,11 @@ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuara
|
||||
FulfillmentErrorCode::ProjectionError(ref e) => {
|
||||
self.report_projection_error(&error.obligation, e)
|
||||
}
|
||||
FulfillmentErrorCode::Ambiguity { overflow: false } => {
|
||||
FulfillmentErrorCode::Ambiguity { overflow: None } => {
|
||||
self.maybe_report_ambiguity(&error.obligation)
|
||||
}
|
||||
FulfillmentErrorCode::Ambiguity { overflow: true } => {
|
||||
self.report_overflow_no_abort(error.obligation.clone())
|
||||
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
|
||||
self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
|
||||
}
|
||||
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
|
||||
.report_mismatched_types(
|
||||
@ -1910,6 +1916,9 @@ fn report_similar_impl_candidates(
|
||||
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
|
||||
},
|
||||
);
|
||||
if cand.references_error() {
|
||||
return false;
|
||||
}
|
||||
err.highlighted_help(vec![
|
||||
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
|
||||
StringPart::highlighted("is"),
|
||||
@ -1934,7 +1943,8 @@ fn report_similar_impl_candidates(
|
||||
}
|
||||
|
||||
let other = if other { "other " } else { "" };
|
||||
let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diag<'_>| {
|
||||
let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diag<'_>| {
|
||||
candidates.retain(|tr| !tr.references_error());
|
||||
if candidates.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ fn collect_remaining_errors(
|
||||
_infcx: &InferCtxt<'tcx>,
|
||||
) -> Vec<FulfillmentError<'tcx>> {
|
||||
self.predicates
|
||||
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: false })
|
||||
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: None })
|
||||
.into_iter()
|
||||
.map(to_fulfillment_error)
|
||||
.collect()
|
||||
|
@ -39,6 +39,7 @@ pub struct OverlapError<'tcx> {
|
||||
pub self_ty: Option<Ty<'tcx>>,
|
||||
pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
|
||||
pub involves_placeholder: bool,
|
||||
pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
|
||||
}
|
||||
|
||||
/// Given the generic parameters for the requested impl, translate it to the generic parameters
|
||||
@ -435,6 +436,14 @@ fn decorate<'tcx, G: EmissionGuarantee>(
|
||||
if overlap.involves_placeholder {
|
||||
coherence::add_placeholder_note(err);
|
||||
}
|
||||
|
||||
if !overlap.overflowing_predicates.is_empty() {
|
||||
coherence::suggest_increasing_recursion_limit(
|
||||
tcx,
|
||||
err,
|
||||
&overlap.overflowing_predicates,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let msg = DelayDm(|| {
|
||||
|
@ -103,6 +103,7 @@ fn insert(
|
||||
self_ty: self_ty.has_concrete_skeleton().then_some(self_ty),
|
||||
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
|
||||
involves_placeholder: overlap.involves_placeholder,
|
||||
overflowing_predicates: overlap.overflowing_predicates,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
use crate::compiler_interface::with;
|
||||
use crate::error;
|
||||
use crate::mir::FieldIdx;
|
||||
use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx};
|
||||
use crate::target::{MachineInfo, MachineSize as Size};
|
||||
use crate::ty::{Align, IndexedVal, Ty, VariantIdx};
|
||||
use crate::Error;
|
||||
use crate::Opaque;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
@ -100,7 +104,7 @@ pub fn is_sized(&self) -> bool {
|
||||
|
||||
/// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
|
||||
pub fn is_1zst(&self) -> bool {
|
||||
self.is_sized() && self.size == 0 && self.abi_align == 1
|
||||
self.is_sized() && self.size.bits() == 0 && self.abi_align == 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,8 +249,175 @@ pub fn is_unsized(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// We currently do not support `Scalar`, and use opaque instead.
|
||||
type Scalar = Opaque;
|
||||
/// Information about one scalar component of a Rust type.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum Scalar {
|
||||
Initialized {
|
||||
/// The primitive type used to represent this value.
|
||||
value: Primitive,
|
||||
/// The range that represents valid values.
|
||||
/// The range must be valid for the `primitive` size.
|
||||
valid_range: WrappingRange,
|
||||
},
|
||||
Union {
|
||||
/// Unions never have niches, so there is no `valid_range`.
|
||||
/// Even for unions, we need to use the correct registers for the kind of
|
||||
/// values inside the union, so we keep the `Primitive` type around.
|
||||
/// It is also used to compute the size of the scalar.
|
||||
value: Primitive,
|
||||
},
|
||||
}
|
||||
|
||||
impl Scalar {
|
||||
pub fn has_niche(&self, target: &MachineInfo) -> bool {
|
||||
match self {
|
||||
Scalar::Initialized { value, valid_range } => {
|
||||
!valid_range.is_full(value.size(target)).unwrap()
|
||||
}
|
||||
Scalar::Union { .. } => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fundamental unit of memory access and layout.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum Primitive {
|
||||
/// The `bool` is the signedness of the `Integer` type.
|
||||
///
|
||||
/// One would think we would not care about such details this low down,
|
||||
/// but some ABIs are described in terms of C types and ISAs where the
|
||||
/// integer arithmetic is done on {sign,zero}-extended registers, e.g.
|
||||
/// a negative integer passed by zero-extension will appear positive in
|
||||
/// the callee, and most operations on it will produce the wrong values.
|
||||
Int {
|
||||
length: IntegerLength,
|
||||
signed: bool,
|
||||
},
|
||||
Float {
|
||||
length: FloatLength,
|
||||
},
|
||||
Pointer(AddressSpace),
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
pub fn size(self, target: &MachineInfo) -> Size {
|
||||
match self {
|
||||
Primitive::Int { length, .. } => Size::from_bits(length.bits()),
|
||||
Primitive::Float { length } => Size::from_bits(length.bits()),
|
||||
Primitive::Pointer(_) => target.pointer_width,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum representing the existing integer lengths.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub enum IntegerLength {
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
}
|
||||
|
||||
/// Enum representing the existing float lengths.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub enum FloatLength {
|
||||
F16,
|
||||
F32,
|
||||
F64,
|
||||
F128,
|
||||
}
|
||||
|
||||
impl IntegerLength {
|
||||
pub fn bits(self) -> usize {
|
||||
match self {
|
||||
IntegerLength::I8 => 8,
|
||||
IntegerLength::I16 => 16,
|
||||
IntegerLength::I32 => 32,
|
||||
IntegerLength::I64 => 64,
|
||||
IntegerLength::I128 => 128,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatLength {
|
||||
pub fn bits(self) -> usize {
|
||||
match self {
|
||||
FloatLength::F16 => 16,
|
||||
FloatLength::F32 => 32,
|
||||
FloatLength::F64 => 64,
|
||||
FloatLength::F128 => 128,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier that specifies the address space that some operation
|
||||
/// should operate on. Special address spaces have an effect on code generation,
|
||||
/// depending on the target and the address spaces it implements.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct AddressSpace(pub u32);
|
||||
|
||||
impl AddressSpace {
|
||||
/// The default address space, corresponding to data space.
|
||||
pub const DATA: Self = AddressSpace(0);
|
||||
}
|
||||
|
||||
/// Inclusive wrap-around range of valid values (bitwise representation), that is, if
|
||||
/// start > end, it represents `start..=MAX`, followed by `0..=end`.
|
||||
///
|
||||
/// That is, for an i8 primitive, a range of `254..=2` means following
|
||||
/// sequence:
|
||||
///
|
||||
/// 254 (-2), 255 (-1), 0, 1, 2
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct WrappingRange {
|
||||
pub start: u128,
|
||||
pub end: u128,
|
||||
}
|
||||
|
||||
impl WrappingRange {
|
||||
/// Returns `true` if `size` completely fills the range.
|
||||
#[inline]
|
||||
pub fn is_full(&self, size: Size) -> Result<bool, Error> {
|
||||
let Some(max_value) = size.unsigned_int_max() else {
|
||||
return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits()));
|
||||
};
|
||||
if self.start <= max_value && self.end <= max_value {
|
||||
Ok(self.start == 0 && max_value == self.end)
|
||||
} else {
|
||||
Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if `v` is contained in the range.
|
||||
#[inline(always)]
|
||||
pub fn contains(&self, v: u128) -> bool {
|
||||
if self.wraps_around() {
|
||||
self.start <= v || v <= self.end
|
||||
} else {
|
||||
self.start <= v && v <= self.end
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the range wraps around.
|
||||
/// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`.
|
||||
/// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`.
|
||||
#[inline]
|
||||
pub fn wraps_around(&self) -> bool {
|
||||
self.start > self.end
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for WrappingRange {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.start > self.end {
|
||||
write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
|
||||
} else {
|
||||
write!(fmt, "{}..={}", self.start, self.end)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// General language calling conventions.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -5,12 +5,14 @@
|
||||
//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
|
||||
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::{error, fmt, io};
|
||||
use std::{fmt, io};
|
||||
|
||||
macro_rules! error {
|
||||
($fmt: literal $(,)?) => { Error(format!($fmt)) };
|
||||
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use error;
|
||||
|
||||
/// An error type used to represent an error that has already been reported by the compiler.
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
@ -72,8 +74,9 @@ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {}
|
||||
impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl<T> std::error::Error for CompilerError<T> where T: Display + Debug {}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
|
@ -30,21 +30,29 @@ pub enum Endian {
|
||||
}
|
||||
|
||||
/// Represent the size of a component.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct MachineSize {
|
||||
num_bits: usize,
|
||||
}
|
||||
|
||||
impl MachineSize {
|
||||
#[inline(always)]
|
||||
pub fn bytes(self) -> usize {
|
||||
self.num_bits / 8
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn bits(self) -> usize {
|
||||
self.num_bits
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_bits(num_bits: usize) -> MachineSize {
|
||||
MachineSize { num_bits }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unsigned_int_max(self) -> Option<u128> {
|
||||
(self.num_bits <= 128).then(|| u128::MAX >> (128 - self.bits()))
|
||||
}
|
||||
}
|
||||
|
@ -324,7 +324,9 @@ pub fn is_str(&self) -> bool {
|
||||
|
||||
#[inline]
|
||||
pub fn is_cstr(&self) -> bool {
|
||||
let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else { return false };
|
||||
let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else {
|
||||
return false;
|
||||
};
|
||||
with(|cx| cx.adt_is_cstr(*def))
|
||||
}
|
||||
|
||||
@ -1032,10 +1034,13 @@ pub struct BoundTy {
|
||||
}
|
||||
|
||||
pub type Bytes = Vec<Option<u8>>;
|
||||
|
||||
/// Size in bytes.
|
||||
pub type Size = usize;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct Prov(pub AllocId);
|
||||
|
||||
pub type Align = u64;
|
||||
pub type Promoted = u32;
|
||||
pub type InitMaskMaterialized = Vec<u64>;
|
||||
|
@ -2519,7 +2519,7 @@ pub fn contains(&self, x: &T) -> bool
|
||||
cmp::SliceContains::slice_contains(x, self)
|
||||
}
|
||||
|
||||
/// Returns `true` if `needle` is a prefix of the slice.
|
||||
/// Returns `true` if `needle` is a prefix of the slice or equal to the slice.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2527,6 +2527,7 @@ pub fn contains(&self, x: &T) -> bool
|
||||
/// let v = [10, 40, 30];
|
||||
/// assert!(v.starts_with(&[10]));
|
||||
/// assert!(v.starts_with(&[10, 40]));
|
||||
/// assert!(v.starts_with(&v));
|
||||
/// assert!(!v.starts_with(&[50]));
|
||||
/// assert!(!v.starts_with(&[10, 50]));
|
||||
/// ```
|
||||
@ -2549,7 +2550,7 @@ pub fn starts_with(&self, needle: &[T]) -> bool
|
||||
self.len() >= n && needle == &self[..n]
|
||||
}
|
||||
|
||||
/// Returns `true` if `needle` is a suffix of the slice.
|
||||
/// Returns `true` if `needle` is a suffix of the slice or equal to the slice.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -2557,6 +2558,7 @@ pub fn starts_with(&self, needle: &[T]) -> bool
|
||||
/// let v = [10, 40, 30];
|
||||
/// assert!(v.ends_with(&[30]));
|
||||
/// assert!(v.ends_with(&[40, 30]));
|
||||
/// assert!(v.ends_with(&v));
|
||||
/// assert!(!v.ends_with(&[50]));
|
||||
/// assert!(!v.ends_with(&[50, 30]));
|
||||
/// ```
|
||||
@ -2582,7 +2584,8 @@ pub fn ends_with(&self, needle: &[T]) -> bool
|
||||
/// Returns a subslice with the prefix removed.
|
||||
///
|
||||
/// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`.
|
||||
/// If `prefix` is empty, simply returns the original slice.
|
||||
/// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the
|
||||
/// original slice, returns an empty slice.
|
||||
///
|
||||
/// If the slice does not start with `prefix`, returns `None`.
|
||||
///
|
||||
@ -2592,6 +2595,7 @@ pub fn ends_with(&self, needle: &[T]) -> bool
|
||||
/// let v = &[10, 40, 30];
|
||||
/// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
|
||||
/// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
|
||||
/// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..]));
|
||||
/// assert_eq!(v.strip_prefix(&[50]), None);
|
||||
/// assert_eq!(v.strip_prefix(&[10, 50]), None);
|
||||
///
|
||||
@ -2620,7 +2624,8 @@ pub fn strip_prefix<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> Op
|
||||
/// Returns a subslice with the suffix removed.
|
||||
///
|
||||
/// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`.
|
||||
/// If `suffix` is empty, simply returns the original slice.
|
||||
/// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the
|
||||
/// original slice, returns an empty slice.
|
||||
///
|
||||
/// If the slice does not end with `suffix`, returns `None`.
|
||||
///
|
||||
@ -2630,6 +2635,7 @@ pub fn strip_prefix<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> Op
|
||||
/// let v = &[10, 40, 30];
|
||||
/// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
|
||||
/// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..]));
|
||||
/// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..]));
|
||||
/// assert_eq!(v.strip_suffix(&[50]), None);
|
||||
/// assert_eq!(v.strip_suffix(&[50, 30]), None);
|
||||
/// ```
|
||||
|
@ -26,6 +26,7 @@ fn main() {
|
||||
"InstrProfilingMerge.c",
|
||||
"InstrProfilingMergeFile.c",
|
||||
"InstrProfilingNameVar.c",
|
||||
"InstrProfilingPlatformAIX.c",
|
||||
"InstrProfilingPlatformDarwin.c",
|
||||
"InstrProfilingPlatformFuchsia.c",
|
||||
"InstrProfilingPlatformLinux.c",
|
||||
|
@ -19,12 +19,10 @@ struct FooDefault<'a> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct TupleDefault(bool, i32, u64);
|
||||
|
||||
|
||||
|
||||
struct FooND1 {
|
||||
a: bool,
|
||||
}
|
||||
@ -73,7 +71,6 @@ impl Default for FooNDVec {
|
||||
struct StrDefault<'a>(&'a str);
|
||||
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct AlreadyDerived(i32, bool);
|
||||
|
||||
@ -96,7 +93,6 @@ mac!(0);
|
||||
#[derive(Default)]
|
||||
struct Y(u32);
|
||||
|
||||
|
||||
struct RustIssue26925<T> {
|
||||
a: Option<T>,
|
||||
}
|
||||
@ -132,12 +128,10 @@ struct WithoutSelfCurly {
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
struct WithoutSelfParan(bool);
|
||||
|
||||
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7655
|
||||
|
||||
pub struct SpecializedImpl2<T> {
|
||||
@ -184,7 +178,6 @@ pub struct RepeatDefault1 {
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct RepeatDefault2 {
|
||||
a: [i8; 33],
|
||||
}
|
||||
@ -216,7 +209,6 @@ pub enum SimpleEnum {
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub enum NonExhaustiveEnum {
|
||||
Foo,
|
||||
#[non_exhaustive]
|
||||
|
@ -5,7 +5,6 @@
|
||||
struct Foo;
|
||||
|
||||
|
||||
|
||||
// shouldn't cause an error
|
||||
struct Bar;
|
||||
|
||||
@ -19,5 +18,4 @@ impl Drop for Bar {
|
||||
struct Baz;
|
||||
|
||||
|
||||
|
||||
fn main() {}
|
||||
|
@ -6,13 +6,10 @@
|
||||
extern crate proc_macros;
|
||||
use proc_macros::external;
|
||||
|
||||
|
||||
pub fn must_use_default() {}
|
||||
|
||||
|
||||
pub fn must_use_unit() -> () {}
|
||||
|
||||
|
||||
pub fn must_use_with_note() {}
|
||||
|
||||
fn main() {
|
||||
|
@ -4,7 +4,6 @@
|
||||
use core;
|
||||
|
||||
|
||||
|
||||
use serde as edres;
|
||||
|
||||
pub use serde;
|
||||
|
@ -3797,9 +3797,9 @@
|
||||
"ui/rust-2018/uniform-paths/issue-56596-2.rs",
|
||||
"ui/rust-2018/uniform-paths/issue-56596.rs",
|
||||
"ui/rust-2018/uniform-paths/issue-87932.rs",
|
||||
"ui/sanitize/issue-111184-coroutine-witness.rs",
|
||||
"ui/sanitize/issue-114275-cfi-const-expr-in-arry-len.rs",
|
||||
"ui/sanitize/issue-72154-lifetime-markers.rs",
|
||||
"ui/sanitizer/issue-111184-cfi-coroutine-witness.rs",
|
||||
"ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs",
|
||||
"ui/sanitizer/issue-72154-address-lifetime-markers.rs",
|
||||
"ui/self/issue-61882-2.rs",
|
||||
"ui/self/issue-61882.rs",
|
||||
"ui/simd/intrinsic/issue-85855.rs",
|
||||
|
@ -42,15 +42,11 @@
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
|
||||
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
|
||||
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
- falseEdge -> [real: bb20, imaginary: bb4];
|
||||
- }
|
||||
-
|
||||
- bb4: {
|
||||
StorageLive(_15);
|
||||
_15 = (_2.1: bool);
|
||||
StorageLive(_16);
|
||||
@ -59,8 +55,12 @@
|
||||
+ goto -> bb16;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
- falseEdge -> [real: bb20, imaginary: bb3];
|
||||
- }
|
||||
-
|
||||
- bb5: {
|
||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
||||
- falseEdge -> [real: bb13, imaginary: bb4];
|
||||
- }
|
||||
-
|
||||
- bb6: {
|
||||
@ -68,7 +68,6 @@
|
||||
- }
|
||||
-
|
||||
- bb7: {
|
||||
+ bb4: {
|
||||
_0 = const 1_i32;
|
||||
- drop(_7) -> [return: bb18, unwind: bb25];
|
||||
+ drop(_7) -> [return: bb15, unwind: bb22];
|
||||
@ -184,7 +183,7 @@
|
||||
StorageDead(_12);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
||||
- falseEdge -> [real: bb2, imaginary: bb4];
|
||||
+ goto -> bb2;
|
||||
}
|
||||
|
||||
|
@ -42,15 +42,11 @@
|
||||
}
|
||||
|
||||
bb2: {
|
||||
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
|
||||
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
|
||||
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
||||
}
|
||||
|
||||
bb3: {
|
||||
- falseEdge -> [real: bb20, imaginary: bb4];
|
||||
- }
|
||||
-
|
||||
- bb4: {
|
||||
StorageLive(_15);
|
||||
_15 = (_2.1: bool);
|
||||
StorageLive(_16);
|
||||
@ -59,8 +55,12 @@
|
||||
+ goto -> bb16;
|
||||
}
|
||||
|
||||
bb4: {
|
||||
- falseEdge -> [real: bb20, imaginary: bb3];
|
||||
- }
|
||||
-
|
||||
- bb5: {
|
||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
||||
- falseEdge -> [real: bb13, imaginary: bb4];
|
||||
- }
|
||||
-
|
||||
- bb6: {
|
||||
@ -68,7 +68,6 @@
|
||||
- }
|
||||
-
|
||||
- bb7: {
|
||||
+ bb4: {
|
||||
_0 = const 1_i32;
|
||||
- drop(_7) -> [return: bb18, unwind: bb25];
|
||||
+ drop(_7) -> [return: bb15, unwind: bb22];
|
||||
@ -184,7 +183,7 @@
|
||||
StorageDead(_12);
|
||||
StorageDead(_8);
|
||||
StorageDead(_6);
|
||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
||||
- falseEdge -> [real: bb2, imaginary: bb4];
|
||||
+ goto -> bb2;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,6 @@
|
||||
//@ check-pass
|
||||
|
||||
#[doc(include = "external-cross-doc.md")]
|
||||
//~^ WARNING unknown `doc` attribute `include`
|
||||
//~^ ERROR unknown `doc` attribute `include`
|
||||
//~| HELP use `doc = include_str!` instead
|
||||
// FIXME(#85497): make this a deny instead so it's more clear what's happening
|
||||
//~| NOTE on by default
|
||||
//~| WARNING previously accepted
|
||||
//~| NOTE see issue #82730
|
||||
pub struct NeedMoreDocs;
|
||||
|
@ -1,12 +1,10 @@
|
||||
warning: unknown `doc` attribute `include`
|
||||
--> $DIR/doc-include-suggestion.rs:3:7
|
||||
error: unknown `doc` attribute `include`
|
||||
--> $DIR/doc-include-suggestion.rs:1:7
|
||||
|
|
||||
LL | #[doc(include = "external-cross-doc.md")]
|
||||
| ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: `#[warn(invalid_doc_attributes)]` on by default
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -1,14 +1,10 @@
|
||||
#![crate_type = "lib"]
|
||||
#![deny(invalid_doc_attributes)]
|
||||
|
||||
#![doc(test)]
|
||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||
//~^^ WARN this was previously accepted by the compiler
|
||||
#![doc(test = "hello")]
|
||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||
//~^^ WARN this was previously accepted by the compiler
|
||||
#![doc(test(a))]
|
||||
//~^ ERROR unknown `doc(test)` attribute `a`
|
||||
//~^^ WARN this was previously accepted by the compiler
|
||||
|
||||
pub fn foo() {}
|
||||
|
@ -1,34 +1,22 @@
|
||||
error: `#[doc(test(...)]` takes a list of attributes
|
||||
--> $DIR/doc-test-attr.rs:4:8
|
||||
--> $DIR/doc-test-attr.rs:3:8
|
||||
|
|
||||
LL | #![doc(test)]
|
||||
| ^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc-test-attr.rs:2:9
|
||||
|
|
||||
LL | #![deny(invalid_doc_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error: `#[doc(test(...)]` takes a list of attributes
|
||||
--> $DIR/doc-test-attr.rs:7:8
|
||||
--> $DIR/doc-test-attr.rs:5:8
|
||||
|
|
||||
LL | #![doc(test = "hello")]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc(test)` attribute `a`
|
||||
--> $DIR/doc-test-attr.rs:10:13
|
||||
--> $DIR/doc-test-attr.rs:7:13
|
||||
|
|
||||
LL | #![doc(test(a))]
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,25 +1,17 @@
|
||||
#![crate_type = "lib"]
|
||||
#![deny(warnings)]
|
||||
#![doc(as_ptr)]
|
||||
//~^ ERROR unknown `doc` attribute
|
||||
//~^^ WARN
|
||||
|
||||
#[doc(as_ptr)]
|
||||
//~^ ERROR unknown `doc` attribute
|
||||
//~^^ WARN
|
||||
pub fn foo() {}
|
||||
|
||||
#[doc(123)]
|
||||
//~^ ERROR invalid `doc` attribute
|
||||
//~| WARN
|
||||
#[doc("hello", "bar")]
|
||||
//~^ ERROR invalid `doc` attribute
|
||||
//~| WARN
|
||||
//~| ERROR invalid `doc` attribute
|
||||
//~| WARN
|
||||
#[doc(foo::bar, crate::bar::baz = "bye")]
|
||||
//~^ ERROR unknown `doc` attribute
|
||||
//~| WARN
|
||||
//~| ERROR unknown `doc` attribute
|
||||
//~| WARN
|
||||
fn bar() {}
|
||||
|
@ -1,71 +1,46 @@
|
||||
error: unknown `doc` attribute `as_ptr`
|
||||
--> $DIR/doc-attr.rs:7:7
|
||||
--> $DIR/doc-attr.rs:5:7
|
||||
|
|
||||
LL | #[doc(as_ptr)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc-attr.rs:2:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error: invalid `doc` attribute
|
||||
--> $DIR/doc-attr.rs:12:7
|
||||
--> $DIR/doc-attr.rs:9:7
|
||||
|
|
||||
LL | #[doc(123)]
|
||||
| ^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: invalid `doc` attribute
|
||||
--> $DIR/doc-attr.rs:15:7
|
||||
--> $DIR/doc-attr.rs:11:7
|
||||
|
|
||||
LL | #[doc("hello", "bar")]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: invalid `doc` attribute
|
||||
--> $DIR/doc-attr.rs:15:16
|
||||
--> $DIR/doc-attr.rs:11:16
|
||||
|
|
||||
LL | #[doc("hello", "bar")]
|
||||
| ^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc` attribute `foo::bar`
|
||||
--> $DIR/doc-attr.rs:20:7
|
||||
--> $DIR/doc-attr.rs:14:7
|
||||
|
|
||||
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc` attribute `crate::bar::baz`
|
||||
--> $DIR/doc-attr.rs:20:17
|
||||
--> $DIR/doc-attr.rs:14:17
|
||||
|
|
||||
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc` attribute `as_ptr`
|
||||
--> $DIR/doc-attr.rs:3:8
|
||||
--> $DIR/doc-attr.rs:2:8
|
||||
|
|
||||
LL | #![doc(as_ptr)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
//@ run-rustfix
|
||||
#![deny(warnings)]
|
||||
#![feature(doc_notable_trait)]
|
||||
|
||||
#[doc(notable_trait)]
|
||||
//~^ ERROR unknown `doc` attribute `spotlight`
|
||||
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
trait MyTrait {}
|
||||
|
@ -1,8 +1,6 @@
|
||||
//@ run-rustfix
|
||||
#![deny(warnings)]
|
||||
#![feature(doc_notable_trait)]
|
||||
|
||||
#[doc(spotlight)]
|
||||
//~^ ERROR unknown `doc` attribute `spotlight`
|
||||
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
trait MyTrait {}
|
||||
|
@ -1,19 +1,12 @@
|
||||
error: unknown `doc` attribute `spotlight`
|
||||
--> $DIR/doc-spotlight.rs:5:7
|
||||
--> $DIR/doc-spotlight.rs:4:7
|
||||
|
|
||||
LL | #[doc(spotlight)]
|
||||
| ^^^^^^^^^ help: use `notable_trait` instead
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: `doc(spotlight)` was renamed to `doc(notable_trait)`
|
||||
= note: `doc(spotlight)` is now a no-op
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc-spotlight.rs:2:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -1,11 +1,7 @@
|
||||
#![feature(doc_cfg_hide)]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![doc(cfg_hide = "test")] //~ ERROR
|
||||
//~^ WARN
|
||||
#![doc(cfg_hide)] //~ ERROR
|
||||
//~^ WARN
|
||||
|
||||
#[doc(cfg_hide(doc))] //~ ERROR
|
||||
//~^ WARN
|
||||
pub fn foo() {}
|
||||
|
@ -1,40 +1,27 @@
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/doc_cfg_hide.rs:9:7
|
||||
--> $DIR/doc_cfg_hide.rs:6:7
|
||||
|
|
||||
LL | #[doc(cfg_hide(doc))]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc_cfg_hide.rs:2:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
help: to apply to the crate, use an inner attribute
|
||||
|
|
||||
LL | #![doc(cfg_hide(doc))]
|
||||
| +
|
||||
|
||||
error: `#[doc(cfg_hide(...))]` takes a list of attributes
|
||||
--> $DIR/doc_cfg_hide.rs:4:8
|
||||
--> $DIR/doc_cfg_hide.rs:3:8
|
||||
|
|
||||
LL | #![doc(cfg_hide = "test")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: `#[doc(cfg_hide(...))]` takes a list of attributes
|
||||
--> $DIR/doc_cfg_hide.rs:6:8
|
||||
--> $DIR/doc_cfg_hide.rs:4:8
|
||||
|
|
||||
LL | #![doc(cfg_hide)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,32 +1,25 @@
|
||||
#![crate_type = "lib"]
|
||||
#![deny(warnings)]
|
||||
#![feature(doc_masked)]
|
||||
|
||||
#![doc(masked)]
|
||||
//~^ ERROR this attribute can only be applied to an `extern crate` item
|
||||
//~| WARN is being phased out
|
||||
|
||||
#[doc(test(no_crate_inject))]
|
||||
//~^ ERROR can only be applied at the crate level
|
||||
//~| WARN is being phased out
|
||||
//~| HELP to apply to the crate, use an inner attribute
|
||||
//~| SUGGESTION !
|
||||
#[doc(inline)]
|
||||
//~^ ERROR can only be applied to a `use` item
|
||||
//~| WARN is being phased out
|
||||
pub fn foo() {}
|
||||
|
||||
pub mod bar {
|
||||
#![doc(test(no_crate_inject))]
|
||||
//~^ ERROR can only be applied at the crate level
|
||||
//~| WARN is being phased out
|
||||
|
||||
#[doc(test(no_crate_inject))]
|
||||
//~^ ERROR can only be applied at the crate level
|
||||
//~| WARN is being phased out
|
||||
#[doc(inline)]
|
||||
//~^ ERROR can only be applied to a `use` item
|
||||
//~| WARN is being phased out
|
||||
pub fn baz() {}
|
||||
}
|
||||
|
||||
@ -38,10 +31,8 @@ pub fn baz() {}
|
||||
|
||||
#[doc(masked)]
|
||||
//~^ ERROR this attribute can only be applied to an `extern crate` item
|
||||
//~| WARN is being phased out
|
||||
pub struct Masked;
|
||||
|
||||
#[doc(masked)]
|
||||
//~^ ERROR this attribute cannot be applied to an `extern crate self` item
|
||||
//~| WARN is being phased out
|
||||
pub extern crate self as reexport;
|
||||
|
@ -1,48 +1,37 @@
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:9:7
|
||||
--> $DIR/invalid-doc-attr.rs:7:7
|
||||
|
|
||||
LL | #[doc(test(no_crate_inject))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
note: the lint level is defined here
|
||||
--> $DIR/invalid-doc-attr.rs:2:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
help: to apply to the crate, use an inner attribute
|
||||
|
|
||||
LL | #![doc(test(no_crate_inject))]
|
||||
| +
|
||||
|
||||
error: this attribute can only be applied to a `use` item
|
||||
--> $DIR/invalid-doc-attr.rs:14:7
|
||||
--> $DIR/invalid-doc-attr.rs:11:7
|
||||
|
|
||||
LL | #[doc(inline)]
|
||||
| ^^^^^^ only applicable on `use` items
|
||||
...
|
||||
LL |
|
||||
LL | pub fn foo() {}
|
||||
| ------------ not a `use` item
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:20:12
|
||||
--> $DIR/invalid-doc-attr.rs:16:12
|
||||
|
|
||||
LL | #![doc(test(no_crate_inject))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: conflicting doc inlining attributes
|
||||
--> $DIR/invalid-doc-attr.rs:33:7
|
||||
--> $DIR/invalid-doc-attr.rs:26:7
|
||||
|
|
||||
LL | #[doc(inline)]
|
||||
| ^^^^^^ this attribute...
|
||||
@ -52,61 +41,50 @@ LL | #[doc(no_inline)]
|
||||
= help: remove one of the conflicting attributes
|
||||
|
||||
error: this attribute can only be applied to an `extern crate` item
|
||||
--> $DIR/invalid-doc-attr.rs:39:7
|
||||
--> $DIR/invalid-doc-attr.rs:32:7
|
||||
|
|
||||
LL | #[doc(masked)]
|
||||
| ^^^^^^ only applicable on `extern crate` items
|
||||
...
|
||||
LL |
|
||||
LL | pub struct Masked;
|
||||
| ----------------- not an `extern crate` item
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
|
||||
|
||||
error: this attribute cannot be applied to an `extern crate self` item
|
||||
--> $DIR/invalid-doc-attr.rs:44:7
|
||||
--> $DIR/invalid-doc-attr.rs:36:7
|
||||
|
|
||||
LL | #[doc(masked)]
|
||||
| ^^^^^^ not applicable on `extern crate self` items
|
||||
...
|
||||
LL |
|
||||
LL | pub extern crate self as reexport;
|
||||
| --------------------------------- `extern crate self` defined here
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: this attribute can only be applied to an `extern crate` item
|
||||
--> $DIR/invalid-doc-attr.rs:5:8
|
||||
--> $DIR/invalid-doc-attr.rs:4:8
|
||||
|
|
||||
LL | #![doc(masked)]
|
||||
| ^^^^^^ only applicable on `extern crate` items
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
|
||||
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:24:11
|
||||
--> $DIR/invalid-doc-attr.rs:19:11
|
||||
|
|
||||
LL | #[doc(test(no_crate_inject))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: this attribute can only be applied to a `use` item
|
||||
--> $DIR/invalid-doc-attr.rs:27:11
|
||||
--> $DIR/invalid-doc-attr.rs:21:11
|
||||
|
|
||||
LL | #[doc(inline)]
|
||||
| ^^^^^^ only applicable on `use` items
|
||||
...
|
||||
LL |
|
||||
LL | pub fn baz() {}
|
||||
| ------------ not a `use` item
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
@ -19,8 +19,12 @@
|
||||
extern crate stable_mir;
|
||||
|
||||
use rustc_smir::rustc_internal;
|
||||
use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
|
||||
use stable_mir::abi::{
|
||||
ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
|
||||
VariantsShape,
|
||||
};
|
||||
use stable_mir::mir::mono::Instance;
|
||||
use stable_mir::target::MachineInfo;
|
||||
use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::convert::TryFrom;
|
||||
@ -39,11 +43,12 @@ fn test_stable_mir() -> ControlFlow<()> {
|
||||
let instance = Instance::try_from(target_fn).unwrap();
|
||||
let fn_abi = instance.fn_abi().unwrap();
|
||||
assert_eq!(fn_abi.conv, CallConvention::Rust);
|
||||
assert_eq!(fn_abi.args.len(), 2);
|
||||
assert_eq!(fn_abi.args.len(), 3);
|
||||
|
||||
check_ignore(&fn_abi.args[0]);
|
||||
check_primitive(&fn_abi.args[1]);
|
||||
check_result(fn_abi.ret);
|
||||
check_niche(&fn_abi.args[2]);
|
||||
check_result(&fn_abi.ret);
|
||||
|
||||
// Test variadic function.
|
||||
let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
|
||||
@ -85,7 +90,7 @@ fn check_primitive(abi: &ArgAbi) {
|
||||
}
|
||||
|
||||
/// Check the return value: `Result<usize, &str>`.
|
||||
fn check_result(abi: ArgAbi) {
|
||||
fn check_result(abi: &ArgAbi) {
|
||||
assert!(abi.ty.kind().is_enum());
|
||||
assert_matches!(abi.mode, PassMode::Indirect { .. });
|
||||
let layout = abi.layout.shape();
|
||||
@ -94,6 +99,25 @@ fn check_result(abi: ArgAbi) {
|
||||
assert_matches!(layout.variants, VariantsShape::Multiple { .. })
|
||||
}
|
||||
|
||||
/// Check the niche information about: `NonZeroU8`
|
||||
fn check_niche(abi: &ArgAbi) {
|
||||
assert!(abi.ty.kind().is_struct());
|
||||
assert_matches!(abi.mode, PassMode::Direct { .. });
|
||||
let layout = abi.layout.shape();
|
||||
assert!(layout.is_sized());
|
||||
assert_eq!(layout.size.bytes(), 1);
|
||||
|
||||
let ValueAbi::Scalar(scalar) = layout.abi else { unreachable!() };
|
||||
assert!(scalar.has_niche(&MachineInfo::target()), "Opps: {:?}", scalar);
|
||||
|
||||
let Scalar::Initialized { value, valid_range } = scalar else { unreachable!() };
|
||||
assert_matches!(value, Primitive::Int { length: IntegerLength::I8, signed: false });
|
||||
assert_eq!(valid_range.start, 1);
|
||||
assert_eq!(valid_range.end, u8::MAX.into());
|
||||
assert!(!valid_range.contains(0));
|
||||
assert!(!valid_range.wraps_around());
|
||||
}
|
||||
|
||||
fn get_item<'a>(
|
||||
items: &'a CrateItems,
|
||||
item: (ItemKind, &str),
|
||||
@ -126,11 +150,16 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
||||
#![feature(c_variadic)]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
|
||||
// We only care about the signature.
|
||||
todo!()
|
||||
}}
|
||||
use std::num::NonZeroU8;
|
||||
|
||||
pub fn fn_abi(
|
||||
ignore: [u8; 0],
|
||||
primitive: char,
|
||||
niche: NonZeroU8,
|
||||
) -> Result<usize, &'static str> {{
|
||||
// We only care about the signature.
|
||||
todo!()
|
||||
}}
|
||||
|
||||
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
|
||||
0
|
||||
|
@ -55,7 +55,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
|
||||
LL | foo::<Demo>()();
|
||||
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
|
||||
|
|
||||
= help: the trait `TraitWAssocConst` is implemented for `{type error}`
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/issue-105330.rs:11:11
|
||||
|
|
||||
@ -92,7 +91,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
|
||||
LL | foo::<Demo>();
|
||||
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
|
||||
|
|
||||
= help: the trait `TraitWAssocConst` is implemented for `{type error}`
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/issue-105330.rs:11:11
|
||||
|
|
||||
|
@ -21,7 +21,6 @@ impl Grault for () {
|
||||
|
||||
impl<T: Grault> Grault for (T,)
|
||||
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||
|
||||
{
|
||||
type A = ();
|
||||
type B = bool;
|
||||
|
@ -1,25 +1,17 @@
|
||||
#![crate_type = "lib"]
|
||||
#![deny(warnings)]
|
||||
#![doc(as_ptr)]
|
||||
//~^ ERROR unknown `doc` attribute
|
||||
//~^^ WARN
|
||||
|
||||
#[doc(as_ptr)]
|
||||
//~^ ERROR unknown `doc` attribute
|
||||
//~^^ WARN
|
||||
pub fn foo() {}
|
||||
|
||||
#[doc(123)]
|
||||
//~^ ERROR invalid `doc` attribute
|
||||
//~| WARN
|
||||
#[doc("hello", "bar")]
|
||||
//~^ ERROR invalid `doc` attribute
|
||||
//~| WARN
|
||||
//~| ERROR invalid `doc` attribute
|
||||
//~| WARN
|
||||
#[doc(foo::bar, crate::bar::baz = "bye")]
|
||||
//~^ ERROR unknown `doc` attribute
|
||||
//~| WARN
|
||||
//~| ERROR unknown `doc` attribute
|
||||
//~| WARN
|
||||
fn bar() {}
|
||||
|
@ -1,71 +1,46 @@
|
||||
error: unknown `doc` attribute `as_ptr`
|
||||
--> $DIR/doc-attr.rs:7:7
|
||||
--> $DIR/doc-attr.rs:5:7
|
||||
|
|
||||
LL | #[doc(as_ptr)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc-attr.rs:2:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error: invalid `doc` attribute
|
||||
--> $DIR/doc-attr.rs:12:7
|
||||
--> $DIR/doc-attr.rs:9:7
|
||||
|
|
||||
LL | #[doc(123)]
|
||||
| ^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: invalid `doc` attribute
|
||||
--> $DIR/doc-attr.rs:15:7
|
||||
--> $DIR/doc-attr.rs:11:7
|
||||
|
|
||||
LL | #[doc("hello", "bar")]
|
||||
| ^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: invalid `doc` attribute
|
||||
--> $DIR/doc-attr.rs:15:16
|
||||
--> $DIR/doc-attr.rs:11:16
|
||||
|
|
||||
LL | #[doc("hello", "bar")]
|
||||
| ^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc` attribute `foo::bar`
|
||||
--> $DIR/doc-attr.rs:20:7
|
||||
--> $DIR/doc-attr.rs:14:7
|
||||
|
|
||||
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc` attribute `crate::bar::baz`
|
||||
--> $DIR/doc-attr.rs:20:17
|
||||
--> $DIR/doc-attr.rs:14:17
|
||||
|
|
||||
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc` attribute `as_ptr`
|
||||
--> $DIR/doc-attr.rs:3:8
|
||||
--> $DIR/doc-attr.rs:2:8
|
||||
|
|
||||
LL | #![doc(as_ptr)]
|
||||
| ^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
#![deny(warnings)]
|
||||
|
||||
#![doc(test(""))]
|
||||
//~^ ERROR `#![doc(test(...)]` does not take a literal
|
||||
//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,17 +1,10 @@
|
||||
error: `#![doc(test(...)]` does not take a literal
|
||||
--> $DIR/doc-test-literal.rs:3:13
|
||||
--> $DIR/doc-test-literal.rs:1:13
|
||||
|
|
||||
LL | #![doc(test(""))]
|
||||
| ^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc-test-literal.rs:1:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -11,8 +11,7 @@ fn f(u8) {} //~ WARN anonymous parameters are deprecated
|
||||
pub mod submodule {
|
||||
// Error since this is a `future_incompatible` lint
|
||||
#![doc(test(some_test))]
|
||||
//~^ ERROR this attribute can only be applied at the crate level
|
||||
//~| WARN this was previously accepted by the compiler
|
||||
//~^ ERROR this attribute can only be applied at the crate level
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -14,15 +14,8 @@ error: this attribute can only be applied at the crate level
|
||||
LL | #![doc(test(some_test))]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
note: the lint level is defined here
|
||||
--> $DIR/future-incompatible-lint-group.rs:3:9
|
||||
|
|
||||
LL | #![deny(future_incompatible)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(future_incompatible)]`
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
|
@ -2,10 +2,8 @@
|
||||
#![allow(dead_code)]
|
||||
#![deny(no_mangle_generic_items)]
|
||||
|
||||
|
||||
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
|
||||
|
||||
|
||||
pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-form
|
||||
LL | for<'a> &'a mut Self:;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`)
|
||||
note: required by a bound in `Bar`
|
||||
--> $DIR/issue-95230.rs:9:13
|
||||
|
|
||||
|
@ -27,10 +27,8 @@ use issue_52891::{l,
|
||||
use issue_52891::a::inner;
|
||||
use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times
|
||||
|
||||
|
||||
//~^ ERROR `issue_52891` is defined multiple times
|
||||
|
||||
|
||||
#[macro_use]
|
||||
use issue_52891::n; //~ ERROR `n` is defined multiple times
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
#![deny(unused_imports)]
|
||||
|
||||
// Check that attributes get removed too. See #87973.
|
||||
|
||||
//~^ ERROR unused import
|
||||
|
||||
fn main() {}
|
||||
|
76
tests/ui/inference/stmts-as-exp-105431.rs
Normal file
76
tests/ui/inference/stmts-as-exp-105431.rs
Normal file
@ -0,0 +1,76 @@
|
||||
#![allow(unused)]
|
||||
|
||||
fn test_if() -> i32 {
|
||||
let x = if true {
|
||||
eprintln!("hello");
|
||||
3;
|
||||
}
|
||||
else {
|
||||
4;
|
||||
};
|
||||
x //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn test_if_without_binding() -> i32 {
|
||||
if true { //~ ERROR mismatched types
|
||||
eprintln!("hello");
|
||||
3;
|
||||
}
|
||||
else { //~ ERROR mismatched types
|
||||
4;
|
||||
}
|
||||
}
|
||||
|
||||
fn test_match() -> i32 {
|
||||
let v = 1;
|
||||
let res = match v {
|
||||
1 => { 1; }
|
||||
_ => { 2; }
|
||||
};
|
||||
res //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn test_match_match_without_binding() -> i32 {
|
||||
let v = 1;
|
||||
match v {
|
||||
1 => { 1; } //~ ERROR mismatched types
|
||||
_ => { 2; } //~ ERROR mismatched types
|
||||
}
|
||||
}
|
||||
|
||||
fn test_match_arm_different_types() -> i32 {
|
||||
let v = 1;
|
||||
let res = match v {
|
||||
1 => { if 1 < 2 { 1 } else { 2 } }
|
||||
_ => { 2; } //~ ERROR `match` arms have incompatible types
|
||||
};
|
||||
res
|
||||
}
|
||||
|
||||
fn test_if_match_mixed() -> i32 {
|
||||
let x = if true {
|
||||
3;
|
||||
} else {
|
||||
match 1 {
|
||||
1 => { 1 }
|
||||
_ => { 2 }
|
||||
};
|
||||
};
|
||||
x //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn test_if_match_mixed_failed() -> i32 {
|
||||
let x = if true {
|
||||
3;
|
||||
} else {
|
||||
// because this is a tailed expr, so we won't check deeper
|
||||
match 1 {
|
||||
1 => { 33; }
|
||||
_ => { 44; }
|
||||
}
|
||||
};
|
||||
x //~ ERROR mismatched types
|
||||
}
|
||||
|
||||
|
||||
fn main() {}
|
129
tests/ui/inference/stmts-as-exp-105431.stderr
Normal file
129
tests/ui/inference/stmts-as-exp-105431.stderr
Normal file
@ -0,0 +1,129 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:11:5
|
||||
|
|
||||
LL | fn test_if() -> i32 {
|
||||
| --- expected `i32` because of return type
|
||||
...
|
||||
LL | x
|
||||
| ^ expected `i32`, found `()`
|
||||
|
|
||||
help: remove this semicolon to return this value
|
||||
|
|
||||
LL - 3;
|
||||
LL + 3
|
||||
|
|
||||
help: remove this semicolon to return this value
|
||||
|
|
||||
LL - 4;
|
||||
LL + 4
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:15:13
|
||||
|
|
||||
LL | if true {
|
||||
| _____________^
|
||||
LL | | eprintln!("hello");
|
||||
LL | | 3;
|
||||
| | - help: remove this semicolon to return this value
|
||||
LL | | }
|
||||
| |_____^ expected `i32`, found `()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:19:10
|
||||
|
|
||||
LL | else {
|
||||
| __________^
|
||||
LL | | 4;
|
||||
| | - help: remove this semicolon to return this value
|
||||
LL | | }
|
||||
| |_____^ expected `i32`, found `()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:30:5
|
||||
|
|
||||
LL | fn test_match() -> i32 {
|
||||
| --- expected `i32` because of return type
|
||||
...
|
||||
LL | res
|
||||
| ^^^ expected `i32`, found `()`
|
||||
|
|
||||
help: remove this semicolon to return this value
|
||||
|
|
||||
LL - 1 => { 1; }
|
||||
LL + 1 => { 1 }
|
||||
|
|
||||
help: remove this semicolon to return this value
|
||||
|
|
||||
LL - _ => { 2; }
|
||||
LL + _ => { 2 }
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:36:14
|
||||
|
|
||||
LL | 1 => { 1; }
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | help: remove this semicolon to return this value
|
||||
| expected `i32`, found `()`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:37:14
|
||||
|
|
||||
LL | _ => { 2; }
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | help: remove this semicolon to return this value
|
||||
| expected `i32`, found `()`
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/stmts-as-exp-105431.rs:45:16
|
||||
|
|
||||
LL | let res = match v {
|
||||
| _______________-
|
||||
LL | | 1 => { if 1 < 2 { 1 } else { 2 } }
|
||||
| | ------------------------- this is found to be of type `{integer}`
|
||||
LL | | _ => { 2; }
|
||||
| | ^-
|
||||
| | ||
|
||||
| | |help: consider removing this semicolon
|
||||
| | expected integer, found `()`
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:59:5
|
||||
|
|
||||
LL | fn test_if_match_mixed() -> i32 {
|
||||
| --- expected `i32` because of return type
|
||||
...
|
||||
LL | x
|
||||
| ^ expected `i32`, found `()`
|
||||
|
|
||||
help: remove this semicolon to return this value
|
||||
|
|
||||
LL - 3;
|
||||
LL + 3
|
||||
|
|
||||
help: remove this semicolon to return this value
|
||||
|
|
||||
LL - };
|
||||
LL + }
|
||||
|
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/stmts-as-exp-105431.rs:72:5
|
||||
|
|
||||
LL | fn test_if_match_mixed_failed() -> i32 {
|
||||
| --- expected `i32` because of return type
|
||||
LL | let x = if true {
|
||||
LL | 3;
|
||||
| - help: remove this semicolon to return this value
|
||||
...
|
||||
LL | x
|
||||
| ^ expected `i32`, found `()`
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
@ -3,8 +3,6 @@ error[E0275]: overflow evaluating the requirement `Loop == _`
|
||||
|
|
||||
LL | impl Loop {}
|
||||
| ^^^^
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)
|
||||
|
||||
error[E0392]: type parameter `T` is never used
|
||||
--> $DIR/inherent-impls-overflow.rs:13:12
|
||||
|
@ -7,11 +7,9 @@
|
||||
// Check that we *reject* leading where-clauses on lazy type aliases.
|
||||
|
||||
pub type Leading0<T>
|
||||
|
||||
= T where String: From<T>;
|
||||
|
||||
pub type Leading1<T, U>
|
||||
|
||||
= (T, U)
|
||||
where
|
||||
U: Copy, String: From<T>;
|
||||
|
@ -7,7 +7,6 @@
|
||||
//~^ ERROR const items should never be `#[no_mangle]`
|
||||
//~| HELP try a static value
|
||||
|
||||
|
||||
//~^ HELP remove this attribute
|
||||
pub fn defiant<T>(_t: T) {}
|
||||
//~^ WARN functions generic over types or consts must be mangled
|
||||
|
11
tests/ui/lint/unused/import_remove_line.fixed
Normal file
11
tests/ui/lint/unused/import_remove_line.fixed
Normal file
@ -0,0 +1,11 @@
|
||||
//@ run-rustfix
|
||||
//@ check-pass
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![warn(unused_imports)]
|
||||
|
||||
//~^ WARN unused imports
|
||||
//~^ WARN unused import
|
||||
|
||||
//~^ WARN unused import
|
||||
//~| WARN unused import
|
13
tests/ui/lint/unused/import_remove_line.rs
Normal file
13
tests/ui/lint/unused/import_remove_line.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//@ run-rustfix
|
||||
//@ check-pass
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![warn(unused_imports)]
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
//~^ WARN unused imports
|
||||
use std::time::SystemTime;
|
||||
//~^ WARN unused import
|
||||
use std::time::SystemTimeError;use std::time::TryFromFloatSecsError;
|
||||
//~^ WARN unused import
|
||||
//~| WARN unused import
|
32
tests/ui/lint/unused/import_remove_line.stderr
Normal file
32
tests/ui/lint/unused/import_remove_line.stderr
Normal file
@ -0,0 +1,32 @@
|
||||
warning: unused imports: `Duration`, `Instant`
|
||||
--> $DIR/import_remove_line.rs:7:17
|
||||
|
|
||||
LL | use std::time::{Duration, Instant};
|
||||
| ^^^^^^^^ ^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/import_remove_line.rs:5:9
|
||||
|
|
||||
LL | #![warn(unused_imports)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `std::time::SystemTime`
|
||||
--> $DIR/import_remove_line.rs:9:5
|
||||
|
|
||||
LL | use std::time::SystemTime;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `std::time::SystemTimeError`
|
||||
--> $DIR/import_remove_line.rs:11:5
|
||||
|
|
||||
LL | use std::time::SystemTimeError;use std::time::TryFromFloatSecsError;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `std::time::TryFromFloatSecsError`
|
||||
--> $DIR/import_remove_line.rs:11:36
|
||||
|
|
||||
LL | use std::time::SystemTimeError;use std::time::TryFromFloatSecsError;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
warning: 4 warnings emitted
|
||||
|
@ -17,6 +17,5 @@ pub enum OwO4 {
|
||||
}
|
||||
|
||||
#[repr(uwu)] //~ERROR: unrecognized representation hint
|
||||
#[doc(owo)] //~WARN: unknown `doc` attribute
|
||||
//~^ WARN: this was previously
|
||||
#[doc(owo)] //~ERROR: unknown `doc` attribute
|
||||
pub struct Owo5;
|
||||
|
@ -30,15 +30,13 @@ LL | #[repr(uwu, u8)]
|
||||
|
|
||||
= help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
|
||||
|
||||
warning: unknown `doc` attribute `owo`
|
||||
error: unknown `doc` attribute `owo`
|
||||
--> $DIR/invalid_repr_list_help.rs:20:7
|
||||
|
|
||||
LL | #[doc(owo)]
|
||||
| ^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
= note: `#[warn(invalid_doc_attributes)]` on by default
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
error[E0552]: unrecognized representation hint
|
||||
--> $DIR/invalid_repr_list_help.rs:19:8
|
||||
@ -48,6 +46,6 @@ LL | #[repr(uwu)]
|
||||
|
|
||||
= help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
|
||||
|
||||
error: aborting due to 5 previous errors; 1 warning emitted
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0552`.
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use std::mem::transmute;
|
||||
|
||||
//~^ ERROR the name `transmute` is defined multiple times
|
||||
|
||||
fn main() {
|
||||
|
@ -9,7 +9,6 @@
|
||||
#![deny(rust_2018_idioms)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
||||
//~^ ERROR unused extern crate
|
||||
|
||||
// Shouldn't suggest changing to `use`, as `bar`
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
// The suggestion span should include the attribute.
|
||||
|
||||
|
||||
//~^ ERROR unused extern crate
|
||||
|
||||
fn main() {}
|
||||
|
@ -2,6 +2,4 @@
|
||||
//~^ NOTE defined here
|
||||
#![doc(x)]
|
||||
//~^ ERROR unknown `doc` attribute `x`
|
||||
//~| WARNING will become a hard error
|
||||
//~| NOTE see issue #82730
|
||||
fn main() {}
|
||||
|
@ -4,8 +4,6 @@ error: unknown `doc` attribute `x`
|
||||
LL | #![doc(x)]
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/deny-invalid-doc-attrs.rs:1:9
|
||||
|
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#[doc(primitive = "foo")]
|
||||
//~^ ERROR unknown `doc` attribute `primitive`
|
||||
//~| WARN
|
||||
mod bar {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -4,8 +4,6 @@ error: unknown `doc` attribute `primitive`
|
||||
LL | #[doc(primitive = "foo")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc-primitive.rs:1:9
|
||||
|
|
||||
|
@ -3,12 +3,9 @@
|
||||
|
||||
#![doc(test)]
|
||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||
//~^^ WARN this was previously accepted by the compiler
|
||||
#![doc(test = "hello")]
|
||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||
//~^^ WARN this was previously accepted by the compiler
|
||||
#![doc(test(a))]
|
||||
//~^ ERROR unknown `doc(test)` attribute `a`
|
||||
//~^^ WARN this was previously accepted by the compiler
|
||||
|
||||
pub fn foo() {}
|
||||
|
@ -4,8 +4,6 @@ error: `#[doc(test(...)]` takes a list of attributes
|
||||
LL | #![doc(test)]
|
||||
| ^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
note: the lint level is defined here
|
||||
--> $DIR/doc-test-attr.rs:2:9
|
||||
|
|
||||
@ -13,22 +11,16 @@ LL | #![deny(invalid_doc_attributes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: `#[doc(test(...)]` takes a list of attributes
|
||||
--> $DIR/doc-test-attr.rs:7:8
|
||||
--> $DIR/doc-test-attr.rs:6:8
|
||||
|
|
||||
LL | #![doc(test = "hello")]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: unknown `doc(test)` attribute `a`
|
||||
--> $DIR/doc-test-attr.rs:10:13
|
||||
--> $DIR/doc-test-attr.rs:8:13
|
||||
|
|
||||
LL | #![doc(test(a))]
|
||||
| ^
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: malformed `cfi_encoding` attribute input
|
||||
--> $DIR/sanitizer-cfi-invalid-attr-cfi-encoding.rs:10:1
|
||||
--> $DIR/cfi-invalid-attr-cfi-encoding.rs:10:1
|
||||
|
|
||||
LL | #[cfi_encoding]
|
||||
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]`
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user