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
137 changed files with 1165 additions and 708 deletions
|
@ -1631,7 +1631,9 @@ impl<'a> Linker for AixLinker<'a> {
|
||||||
|
|
||||||
fn optimize(&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) {}
|
fn control_flow_guard(&mut self) {}
|
||||||
|
|
||||||
|
|
|
@ -428,7 +428,7 @@ impl DiagnosticSpan {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_span_full(
|
fn from_span_full(
|
||||||
span: Span,
|
mut span: Span,
|
||||||
is_primary: bool,
|
is_primary: bool,
|
||||||
label: Option<String>,
|
label: Option<String>,
|
||||||
suggestion: Option<(&String, Applicability)>,
|
suggestion: Option<(&String, Applicability)>,
|
||||||
|
@ -436,6 +436,16 @@ impl DiagnosticSpan {
|
||||||
je: &JsonEmitter,
|
je: &JsonEmitter,
|
||||||
) -> DiagnosticSpan {
|
) -> DiagnosticSpan {
|
||||||
let start = je.sm.lookup_char_pos(span.lo());
|
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 end = je.sm.lookup_char_pos(span.hi());
|
||||||
let backtrace_step = backtrace.next().map(|bt| {
|
let backtrace_step = backtrace.next().map(|bt| {
|
||||||
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
|
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
|
||||||
|
|
|
@ -1744,7 +1744,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
Ty::new_unit(self.tcx),
|
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(
|
self.err_ctxt().consider_returning_binding(
|
||||||
blk,
|
blk,
|
||||||
expected_ty,
|
expected_ty,
|
||||||
|
|
|
@ -22,7 +22,7 @@ use rustc_hir::{
|
||||||
Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
|
||||||
};
|
};
|
||||||
use rustc_hir_analysis::astconv::AstConv;
|
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::lint::in_external_macro;
|
||||||
use rustc_middle::middle::stability::EvalResult;
|
use rustc_middle::middle::stability::EvalResult;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
|
@ -1791,45 +1791,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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(
|
pub(crate) fn is_field_suggestable(
|
||||||
&self,
|
&self,
|
||||||
field: &ty::FieldDef,
|
field: &ty::FieldDef,
|
||||||
|
|
|
@ -1989,6 +1989,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
|
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
|
||||||
self.suggest_await_on_expect_found(cause, span, &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_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::def::CtorKind;
|
||||||
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
|
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
|
||||||
|
use hir::{Local, QPath};
|
||||||
use rustc_data_structures::fx::FxIndexSet;
|
use rustc_data_structures::fx::FxIndexSet;
|
||||||
use rustc_errors::{Applicability, Diag};
|
use rustc_errors::{Applicability, Diag};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def::Res;
|
||||||
|
use rustc_hir::MatchSource;
|
||||||
|
use rustc_hir::Node;
|
||||||
use rustc_middle::traits::{
|
use rustc_middle::traits::{
|
||||||
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
|
||||||
StatementAsExpression,
|
StatementAsExpression,
|
||||||
|
@ -293,6 +298,97 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(
|
pub(super) fn suggest_function_pointers(
|
||||||
&self,
|
&self,
|
||||||
cause: &ObligationCause<'tcx>,
|
cause: &ObligationCause<'tcx>,
|
||||||
|
|
|
@ -135,16 +135,18 @@ pub struct FulfillmentError<'tcx> {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum FulfillmentErrorCode<'tcx> {
|
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>>),
|
Cycle(Vec<PredicateObligation<'tcx>>),
|
||||||
SelectionError(SelectionError<'tcx>),
|
SelectionError(SelectionError<'tcx>),
|
||||||
ProjectionError(MismatchedProjectionTypes<'tcx>),
|
ProjectionError(MismatchedProjectionTypes<'tcx>),
|
||||||
SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
|
SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
|
||||||
ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
|
ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
|
||||||
Ambiguity {
|
Ambiguity {
|
||||||
/// Overflow reported from the new solver `-Znext-solver`, which will
|
/// Overflow is only `Some(suggest_recursion_limit)` when using the next generation
|
||||||
/// be reported as an regular error as opposed to a fatal error.
|
/// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by
|
||||||
overflow: bool,
|
/// emitting a fatal error instead.
|
||||||
|
overflow: Option<bool>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,10 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
|
||||||
ConstEquateError(ref a, ref b) => {
|
ConstEquateError(ref a, ref b) => {
|
||||||
write!(f, "CodeConstEquateError({a:?}, {b:?})")
|
write!(f, "CodeConstEquateError({a:?}, {b:?})")
|
||||||
}
|
}
|
||||||
Ambiguity { overflow: false } => write!(f, "Ambiguity"),
|
Ambiguity { overflow: None } => write!(f, "Ambiguity"),
|
||||||
Ambiguity { overflow: true } => write!(f, "Overflow"),
|
Ambiguity { overflow: Some(suggest_increasing_limit) } => {
|
||||||
|
write!(f, "Overflow({suggest_increasing_limit})")
|
||||||
|
}
|
||||||
Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"),
|
Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3586,18 +3586,9 @@ declare_lint! {
|
||||||
/// being validated. Usually these should be rejected as a hard error,
|
/// being validated. Usually these should be rejected as a hard error,
|
||||||
/// but this lint was introduced to avoid breaking any existing
|
/// but this lint was introduced to avoid breaking any existing
|
||||||
/// crates which included them.
|
/// 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,
|
pub INVALID_DOC_ATTRIBUTES,
|
||||||
Warn,
|
Deny,
|
||||||
"detects invalid `#[doc(...)]` attributes",
|
"detects invalid `#[doc(...)]` attributes",
|
||||||
@future_incompatible = FutureIncompatibleInfo {
|
|
||||||
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
|
||||||
reference: "issue #82730 <https://github.com/rust-lang/rust/issues/82730>",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
|
|
@ -60,7 +60,6 @@ pub enum Certainty {
|
||||||
|
|
||||||
impl Certainty {
|
impl Certainty {
|
||||||
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
|
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.
|
/// Use this function to merge the certainty of multiple nested subgoals.
|
||||||
///
|
///
|
||||||
|
@ -79,15 +78,12 @@ impl Certainty {
|
||||||
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
|
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
|
||||||
(Certainty::Yes, Certainty::Maybe(_)) => other,
|
(Certainty::Yes, Certainty::Maybe(_)) => other,
|
||||||
(Certainty::Maybe(_), Certainty::Yes) => self,
|
(Certainty::Maybe(_), Certainty::Yes) => self,
|
||||||
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
|
(Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
|
||||||
|
Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +95,21 @@ pub enum MaybeCause {
|
||||||
/// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
|
/// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
|
||||||
Ambiguity,
|
Ambiguity,
|
||||||
/// We gave up due to an overflow, most often by hitting the recursion limit.
|
/// 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)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
|
|
|
@ -1097,21 +1097,18 @@ enum TestKind<'tcx> {
|
||||||
variants: BitSet<VariantIdx>,
|
variants: BitSet<VariantIdx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Test what value an integer, `bool`, or `char` has.
|
/// Test what value an integer or `char` has.
|
||||||
SwitchInt {
|
SwitchInt {
|
||||||
/// The type of the value that we're testing.
|
|
||||||
switch_ty: Ty<'tcx>,
|
|
||||||
/// The (ordered) set of values that we test for.
|
/// The (ordered) set of values that we test for.
|
||||||
///
|
///
|
||||||
/// For integers and `char`s we create a branch to each of the values in
|
/// We create a branch to each of the values in `options`, as well as an "otherwise" branch
|
||||||
/// `options`, as well as an "otherwise" branch for all other values, even
|
/// for all other values, even in the (rare) case that `options` is exhaustive.
|
||||||
/// in the (rare) case that `options` is exhaustive.
|
|
||||||
///
|
|
||||||
/// For `bool` we always generate two edges, one for `true` and one for
|
|
||||||
/// `false`.
|
|
||||||
options: FxIndexMap<Const<'tcx>, u128>,
|
options: FxIndexMap<Const<'tcx>, u128>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Test what value a `bool` has.
|
||||||
|
If,
|
||||||
|
|
||||||
/// Test for equality with value, possibly after an unsizing coercion to
|
/// Test for equality with value, possibly after an unsizing coercion to
|
||||||
/// `ty`,
|
/// `ty`,
|
||||||
Eq {
|
Eq {
|
||||||
|
@ -1617,7 +1614,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
// a test like SwitchInt, we may want to add cases based on the candidates that are
|
// a test like SwitchInt, we may want to add cases based on the candidates that are
|
||||||
// available
|
// available
|
||||||
match test.kind {
|
match test.kind {
|
||||||
TestKind::SwitchInt { switch_ty: _, ref mut options } => {
|
TestKind::SwitchInt { ref mut options } => {
|
||||||
for candidate in candidates.iter() {
|
for candidate in candidates.iter() {
|
||||||
if !self.add_cases_to_switch(&match_place, candidate, options) {
|
if !self.add_cases_to_switch(&match_place, candidate, options) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -34,12 +34,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
|
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) => {
|
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
|
||||||
// For integers, we use a `SwitchInt` match, which allows
|
// For integers, we use a `SwitchInt` match, which allows
|
||||||
// us to handle more cases.
|
// us to handle more cases.
|
||||||
TestKind::SwitchInt {
|
TestKind::SwitchInt {
|
||||||
switch_ty: match_pair.pattern.ty,
|
|
||||||
|
|
||||||
// these maps are empty to start; cases are
|
// these maps are empty to start; cases are
|
||||||
// added below in add_cases_to_switch
|
// added below in add_cases_to_switch
|
||||||
options: Default::default(),
|
options: Default::default(),
|
||||||
|
@ -182,34 +182,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestKind::SwitchInt { switch_ty, ref options } => {
|
TestKind::SwitchInt { ref options } => {
|
||||||
let terminator = if *switch_ty.kind() == ty::Bool {
|
// The switch may be inexhaustive so we have a catch-all block
|
||||||
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());
|
debug_assert_eq!(options.len() + 1, target_blocks.len());
|
||||||
let otherwise_block = *target_blocks.last().unwrap();
|
let otherwise_block = *target_blocks.last().unwrap();
|
||||||
let switch_targets = SwitchTargets::new(
|
let switch_targets = SwitchTargets::new(
|
||||||
options.values().copied().zip(target_blocks),
|
options.values().copied().zip(target_blocks),
|
||||||
otherwise_block,
|
otherwise_block,
|
||||||
);
|
);
|
||||||
TerminatorKind::SwitchInt {
|
let terminator = TerminatorKind::SwitchInt {
|
||||||
discr: Operand::Copy(place),
|
discr: Operand::Copy(place),
|
||||||
targets: switch_targets,
|
targets: switch_targets,
|
||||||
}
|
|
||||||
};
|
};
|
||||||
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
|
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 } => {
|
TestKind::Eq { value, ty } => {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let [success_block, fail_block] = *target_blocks else {
|
let [success_block, fail_block] = *target_blocks else {
|
||||||
|
@ -583,24 +578,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
fully_matched = true;
|
fully_matched = true;
|
||||||
Some(variant_index.as_usize())
|
Some(variant_index.as_usize())
|
||||||
}
|
}
|
||||||
(&TestKind::Switch { .. }, _) => {
|
|
||||||
fully_matched = false;
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are performing a switch over integers, then this informs integer
|
// If we are performing a switch over integers, then this informs integer
|
||||||
// equality, but nothing else.
|
// equality, but nothing else.
|
||||||
//
|
//
|
||||||
// FIXME(#29623) we could use PatKind::Range to rule
|
// FIXME(#29623) we could use PatKind::Range to rule
|
||||||
// things out here, in some cases.
|
// 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) =>
|
if is_switch_ty(match_pair.pattern.ty) =>
|
||||||
{
|
{
|
||||||
fully_matched = true;
|
fully_matched = true;
|
||||||
let index = options.get_index_of(value).unwrap();
|
let index = options.get_index_of(value).unwrap();
|
||||||
Some(index)
|
Some(index)
|
||||||
}
|
}
|
||||||
(TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => {
|
(TestKind::SwitchInt { options }, TestCase::Range(range)) => {
|
||||||
fully_matched = false;
|
fully_matched = false;
|
||||||
let not_contained =
|
let not_contained =
|
||||||
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
|
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
|
||||||
|
@ -611,7 +602,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
options.len()
|
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;
|
fully_matched = false;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -703,35 +702,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(&TestKind::Range { .. }, _) => {
|
|
||||||
fully_matched = false;
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
(&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => {
|
// FIXME(#29623): return `Some(1)` when the values are different.
|
||||||
// The call to `self.test(&match_pair)` below is not actually used to generate any
|
(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val })
|
||||||
// MIR. Instead, we just want to compare with `test` (the parameter of the method)
|
if test_val == case_val =>
|
||||||
// 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;
|
fully_matched = true;
|
||||||
Some(0)
|
Some(0)
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
(
|
||||||
|
TestKind::Switch { .. }
|
||||||
|
| TestKind::SwitchInt { .. }
|
||||||
|
| TestKind::Len { .. }
|
||||||
|
| TestKind::Range { .. }
|
||||||
|
| TestKind::Eq { .. },
|
||||||
|
_,
|
||||||
|
) => {
|
||||||
fully_matched = false;
|
fully_matched = false;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if fully_matched {
|
if fully_matched {
|
||||||
|
@ -763,7 +753,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
impl Test<'_> {
|
impl Test<'_> {
|
||||||
pub(super) fn targets(&self) -> usize {
|
pub(super) fn targets(&self) -> usize {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => 2,
|
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } | TestKind::If => 2,
|
||||||
TestKind::Switch { adt_def, .. } => {
|
TestKind::Switch { adt_def, .. } => {
|
||||||
// While the switch that we generate doesn't test for all
|
// While the switch that we generate doesn't test for all
|
||||||
// variants, we have a target for each variant and the
|
// variants, we have a target for each variant and the
|
||||||
|
@ -771,21 +761,13 @@ impl Test<'_> {
|
||||||
// specified have the same block.
|
// specified have the same block.
|
||||||
adt_def.variants().len() + 1
|
adt_def.variants().len() + 1
|
||||||
}
|
}
|
||||||
TestKind::SwitchInt { switch_ty, ref options, .. } => {
|
TestKind::SwitchInt { ref options } => options.len() + 1,
|
||||||
if switch_ty.is_bool() {
|
|
||||||
// `bool` is special cased in `perform_test` to always
|
|
||||||
// branch to two blocks.
|
|
||||||
2
|
|
||||||
} else {
|
|
||||||
options.len() + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_switch_ty(ty: Ty<'_>) -> bool {
|
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>(
|
fn trait_method<'tcx>(
|
||||||
|
|
|
@ -6,11 +6,13 @@ use crate::rustc_smir::{Stable, Tables};
|
||||||
use rustc_middle::ty;
|
use rustc_middle::ty;
|
||||||
use rustc_target::abi::call::Conv;
|
use rustc_target::abi::call::Conv;
|
||||||
use stable_mir::abi::{
|
use stable_mir::abi::{
|
||||||
ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding,
|
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
|
||||||
TyAndLayout, ValueAbi, VariantsShape,
|
LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
|
||||||
|
WrappingRange,
|
||||||
};
|
};
|
||||||
use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx};
|
use stable_mir::opaque;
|
||||||
use stable_mir::{opaque, Opaque};
|
use stable_mir::target::MachineSize as Size;
|
||||||
|
use stable_mir::ty::{Align, IndexedVal, VariantIdx};
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
|
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
|
||||||
type T = VariantIdx;
|
type T = VariantIdx;
|
||||||
|
@ -220,7 +222,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Size {
|
||||||
type T = Size;
|
type T = Size;
|
||||||
|
|
||||||
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||||
self.bytes_usize()
|
Size::from_bits(self.bits_usize())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,9 +235,62 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Align {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
|
impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
|
||||||
type T = Opaque;
|
type T = Scalar;
|
||||||
|
|
||||||
|
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 {
|
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
|
||||||
opaque(self)
|
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 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
||||||
|
|
||||||
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
|
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 {
|
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 {
|
let variance = match direction {
|
||||||
|
|
|
@ -7,6 +7,7 @@ use rustc_infer::infer::{
|
||||||
BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
|
BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
|
||||||
};
|
};
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
|
use rustc_infer::traits::solve::MaybeCause;
|
||||||
use rustc_infer::traits::ObligationCause;
|
use rustc_infer::traits::ObligationCause;
|
||||||
use rustc_middle::infer::canonical::CanonicalVarInfos;
|
use rustc_middle::infer::canonical::CanonicalVarInfos;
|
||||||
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||||
|
@ -29,7 +30,7 @@ use std::ops::ControlFlow;
|
||||||
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||||
|
|
||||||
use super::inspect::ProofTreeBuilder;
|
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::{search_graph::SearchGraph, Goal};
|
||||||
use super::{GoalSource, SolverMode};
|
use super::{GoalSource, SolverMode};
|
||||||
pub use select::InferCtxtSelectExt;
|
pub use select::InferCtxtSelectExt;
|
||||||
|
@ -154,10 +155,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
self.search_graph.solver_mode()
|
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
|
/// Creates a root evaluation context and search graph. This should only be
|
||||||
/// used from outside of any evaluation, and other methods should be preferred
|
/// used from outside of any evaluation, and other methods should be preferred
|
||||||
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
|
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
|
||||||
|
@ -167,7 +164,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
|
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
|
||||||
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
|
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
|
||||||
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
|
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 {
|
let mut ecx = EvalCtxt {
|
||||||
search_graph: &mut search_graph,
|
search_graph: &mut search_graph,
|
||||||
|
@ -388,9 +385,12 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
&& source != GoalSource::ImplWhereBound
|
&& source != GoalSource::ImplWhereBound
|
||||||
};
|
};
|
||||||
|
|
||||||
if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
|
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty
|
||||||
(Certainty::OVERFLOW, false)
|
&& !keep_overflow_constraints()
|
||||||
} else {
|
{
|
||||||
|
return (response.value.certainty, false);
|
||||||
|
}
|
||||||
|
|
||||||
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|
||||||
|| !response.value.external_constraints.opaque_types.is_empty();
|
|| !response.value.external_constraints.opaque_types.is_empty();
|
||||||
|
|
||||||
|
@ -398,7 +398,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
self.instantiate_and_apply_query_response(param_env, original_values, response);
|
self.instantiate_and_apply_query_response(param_env, original_values, response);
|
||||||
(certainty, has_changed)
|
(certainty, has_changed)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
||||||
let Goal { param_env, predicate } = goal;
|
let Goal { param_env, predicate } = goal;
|
||||||
|
@ -466,8 +465,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
||||||
let inspect = self.inspect.new_evaluate_added_goals();
|
let inspect = self.inspect.new_evaluate_added_goals();
|
||||||
let inspect = core::mem::replace(&mut self.inspect, inspect);
|
let inspect = core::mem::replace(&mut self.inspect, inspect);
|
||||||
|
|
||||||
let mut response = Ok(Certainty::OVERFLOW);
|
let mut response = Ok(Certainty::overflow(false));
|
||||||
for _ in 0..self.local_overflow_limit() {
|
for _ in 0..FIXPOINT_STEP_LIMIT {
|
||||||
// FIXME: This match is a bit ugly, it might be nice to change the inspect
|
// 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.
|
// stuff to use a closure instead. which should hopefully simplify this a bit.
|
||||||
match self.evaluate_added_goals_step() {
|
match self.evaluate_added_goals_step() {
|
||||||
|
|
|
@ -24,7 +24,7 @@ use super::{Certainty, InferCtxtEvalExt};
|
||||||
/// It is also likely that we want to use slightly different datastructures
|
/// 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`.
|
/// here as this will have to deal with far more root goals than `evaluate_all`.
|
||||||
pub struct FulfillmentCtxt<'tcx> {
|
pub struct FulfillmentCtxt<'tcx> {
|
||||||
obligations: Vec<PredicateObligation<'tcx>>,
|
obligations: ObligationStorage<'tcx>,
|
||||||
|
|
||||||
/// The snapshot in which this context was created. Using the context
|
/// The snapshot in which this context was created. Using the context
|
||||||
/// outside of this snapshot leads to subtle bugs if the snapshot
|
/// outside of this snapshot leads to subtle bugs if the snapshot
|
||||||
|
@ -33,6 +33,57 @@ pub struct FulfillmentCtxt<'tcx> {
|
||||||
usable_in_snapshot: usize,
|
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> {
|
impl<'tcx> FulfillmentCtxt<'tcx> {
|
||||||
pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
|
pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -40,7 +91,10 @@ impl<'tcx> FulfillmentCtxt<'tcx> {
|
||||||
"new trait solver fulfillment context created when \
|
"new trait solver fulfillment context created when \
|
||||||
infcx is set up for old trait solver"
|
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(
|
fn inspect_evaluated_obligation(
|
||||||
|
@ -67,40 +121,24 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
||||||
obligation: PredicateObligation<'tcx>,
|
obligation: PredicateObligation<'tcx>,
|
||||||
) {
|
) {
|
||||||
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
|
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>> {
|
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||||
self.obligations
|
let mut errors: Vec<_> = self
|
||||||
|
.obligations
|
||||||
|
.pending
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.map(|obligation| {
|
.map(|obligation| fulfillment_error_for_stalled(infcx, obligation))
|
||||||
let code = infcx.probe(|_| {
|
.collect();
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
FulfillmentError {
|
errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError {
|
||||||
obligation: obligation.clone(),
|
root_obligation: obligation.clone(),
|
||||||
code,
|
code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
|
||||||
root_obligation: obligation,
|
obligation,
|
||||||
}
|
}));
|
||||||
})
|
|
||||||
.collect()
|
errors
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
|
||||||
|
@ -108,79 +146,27 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
for i in 0.. {
|
for i in 0.. {
|
||||||
if !infcx.tcx.recursion_limit().value_within_limit(i) {
|
if !infcx.tcx.recursion_limit().value_within_limit(i) {
|
||||||
// Only return true errors that we have accumulated while processing;
|
self.obligations.on_fulfillment_overflow(infcx);
|
||||||
// keep ambiguities around, *including overflows*, because they shouldn't
|
// Only return true errors that we have accumulated while processing.
|
||||||
// be considered true errors.
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut has_changed = false;
|
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 goal = obligation.clone().into();
|
||||||
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0;
|
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0;
|
||||||
self.inspect_evaluated_obligation(infcx, &obligation, &result);
|
self.inspect_evaluated_obligation(infcx, &obligation, &result);
|
||||||
let (changed, certainty) = match result {
|
let (changed, certainty) = match result {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(NoSolution) => {
|
Err(NoSolution) => {
|
||||||
errors.push(FulfillmentError {
|
errors.push(fulfillment_error_for_no_solution(infcx, obligation));
|
||||||
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,
|
|
||||||
});
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
has_changed |= changed;
|
has_changed |= changed;
|
||||||
match certainty {
|
match certainty {
|
||||||
Certainty::Yes => {}
|
Certainty::Yes => {}
|
||||||
Certainty::Maybe(_) => self.obligations.push(obligation),
|
Certainty::Maybe(_) => self.obligations.register(obligation),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,13 +179,84 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||||
self.obligations.clone()
|
self.obligations.clone_pending()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_unstalled_obligations(
|
fn drain_unstalled_obligations(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &InferCtxt<'tcx>,
|
_: &InferCtxt<'tcx>,
|
||||||
) -> Vec<PredicateObligation<'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 use fulfill::FulfillmentCtxt;
|
||||||
pub(crate) use normalize::deeply_normalize_for_diagnostics;
|
pub(crate) use normalize::deeply_normalize_for_diagnostics;
|
||||||
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
|
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum SolverMode {
|
enum SolverMode {
|
||||||
/// Ordinary trait solving, using everywhere except for coherence.
|
/// Ordinary trait solving, using everywhere except for coherence.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::solve::FIXPOINT_STEP_LIMIT;
|
||||||
|
|
||||||
use super::inspect;
|
use super::inspect;
|
||||||
use super::inspect::ProofTreeBuilder;
|
use super::inspect::ProofTreeBuilder;
|
||||||
use super::SolverMode;
|
use super::SolverMode;
|
||||||
|
@ -99,7 +101,6 @@ impl<'tcx> ProvisionalCacheEntry<'tcx> {
|
||||||
|
|
||||||
pub(super) struct SearchGraph<'tcx> {
|
pub(super) struct SearchGraph<'tcx> {
|
||||||
mode: SolverMode,
|
mode: SolverMode,
|
||||||
local_overflow_limit: usize,
|
|
||||||
/// The stack of goals currently being computed.
|
/// The stack of goals currently being computed.
|
||||||
///
|
///
|
||||||
/// An element is *deeper* in the stack if its index is *lower*.
|
/// 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> {
|
impl<'tcx> SearchGraph<'tcx> {
|
||||||
pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
|
pub(super) fn new(mode: SolverMode) -> SearchGraph<'tcx> {
|
||||||
Self {
|
Self {
|
||||||
mode,
|
mode,
|
||||||
local_overflow_limit: tcx.recursion_limit().0.checked_ilog2().unwrap_or(0) as usize,
|
|
||||||
stack: Default::default(),
|
stack: Default::default(),
|
||||||
provisional_cache: Default::default(),
|
provisional_cache: Default::default(),
|
||||||
cycle_participants: Default::default(),
|
cycle_participants: Default::default(),
|
||||||
|
@ -130,10 +130,6 @@ impl<'tcx> SearchGraph<'tcx> {
|
||||||
self.mode
|
self.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn local_overflow_limit(&self) -> usize {
|
|
||||||
self.local_overflow_limit
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update the stack and reached depths on cache hits.
|
/// Update the stack and reached depths on cache hits.
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
|
fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
|
||||||
|
@ -277,7 +273,7 @@ impl<'tcx> SearchGraph<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow);
|
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.
|
// Try to fetch the goal from the global cache.
|
||||||
|
@ -370,7 +366,7 @@ impl<'tcx> SearchGraph<'tcx> {
|
||||||
} else if is_coinductive_cycle {
|
} else if is_coinductive_cycle {
|
||||||
Self::response_no_constraints(tcx, input, Certainty::Yes)
|
Self::response_no_constraints(tcx, input, Certainty::Yes)
|
||||||
} else {
|
} else {
|
||||||
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW)
|
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// No entry, we push this goal on the stack and try to prove it.
|
// No entry, we push this goal on the stack and try to prove it.
|
||||||
|
@ -398,7 +394,7 @@ impl<'tcx> SearchGraph<'tcx> {
|
||||||
// of this we continuously recompute the cycle until the result
|
// of this we continuously recompute the cycle until the result
|
||||||
// of the previous iteration is equal to the final result, at which
|
// of the previous iteration is equal to the final result, at which
|
||||||
// point we are done.
|
// point we are done.
|
||||||
for _ in 0..self.local_overflow_limit() {
|
for _ in 0..FIXPOINT_STEP_LIMIT {
|
||||||
let result = prove_goal(self, inspect);
|
let result = prove_goal(self, inspect);
|
||||||
let stack_entry = self.pop_stack();
|
let stack_entry = self.pop_stack();
|
||||||
debug_assert_eq!(stack_entry.input, input);
|
debug_assert_eq!(stack_entry.input, input);
|
||||||
|
@ -431,7 +427,8 @@ impl<'tcx> SearchGraph<'tcx> {
|
||||||
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
|
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
|
||||||
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
|
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
|
||||||
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
|
} 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 {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
@ -452,7 +449,7 @@ impl<'tcx> SearchGraph<'tcx> {
|
||||||
debug!("canonical cycle overflow");
|
debug!("canonical cycle overflow");
|
||||||
let current_entry = self.pop_stack();
|
let current_entry = self.pop_stack();
|
||||||
debug_assert!(current_entry.has_been_used.is_empty());
|
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)
|
(current_entry, result)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use rustc_errors::{Diag, EmissionGuarantee};
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
|
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::query::NoSolution;
|
||||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
|
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
|
||||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||||
|
@ -35,6 +35,8 @@ use rustc_span::DUMMY_SP;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
|
use super::error_reporting::suggest_new_overflow_limit;
|
||||||
|
|
||||||
/// Whether we do the orphan check relative to this crate or
|
/// Whether we do the orphan check relative to this crate or
|
||||||
/// to some remote crate.
|
/// to some remote crate.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -56,6 +58,9 @@ pub struct OverlapResult<'tcx> {
|
||||||
/// `true` if the overlap might've been permitted before the shift
|
/// `true` if the overlap might've been permitted before the shift
|
||||||
/// to universes.
|
/// to universes.
|
||||||
pub involves_placeholder: bool,
|
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>) {
|
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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum TrackAmbiguityCauses {
|
enum TrackAmbiguityCauses {
|
||||||
Yes,
|
Yes,
|
||||||
|
@ -221,11 +238,13 @@ fn overlap<'tcx>(
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut overflowing_predicates = Vec::new();
|
||||||
if overlap_mode.use_implicit_negative() {
|
if overlap_mode.use_implicit_negative() {
|
||||||
if let Some(_failing_obligation) =
|
match impl_intersection_has_impossible_obligation(selcx, &obligations) {
|
||||||
impl_intersection_has_impossible_obligation(selcx, &obligations)
|
IntersectionHasImpossibleObligations::Yes => return None,
|
||||||
{
|
IntersectionHasImpossibleObligations::No { overflowing_predicates: p } => {
|
||||||
return None;
|
overflowing_predicates = p
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +280,12 @@ fn overlap<'tcx>(
|
||||||
impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
|
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)]
|
#[instrument(level = "debug", skip(infcx), ret)]
|
||||||
|
@ -287,6 +311,19 @@ fn equate_impl_headers<'tcx>(
|
||||||
result.map(|infer_ok| infer_ok.obligations).ok()
|
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
|
/// 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.
|
/// 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>(
|
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligations: &'a [PredicateObligation<'tcx>],
|
obligations: &'a [PredicateObligation<'tcx>],
|
||||||
) -> Option<PredicateObligation<'tcx>> {
|
) -> IntersectionHasImpossibleObligations<'tcx> {
|
||||||
let infcx = selcx.infcx;
|
let infcx = selcx.infcx;
|
||||||
|
|
||||||
if infcx.next_trait_solver() {
|
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.
|
// We only care about the obligations that are *definitely* true errors.
|
||||||
// Ambiguities do not prove the disjointness of two impls.
|
// Ambiguities do not prove the disjointness of two impls.
|
||||||
let mut errors = fulfill_cx.select_where_possible(infcx);
|
let errors = fulfill_cx.select_where_possible(infcx);
|
||||||
errors.pop().map(|err| err.obligation)
|
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 {
|
} else {
|
||||||
obligations
|
IntersectionHasImpossibleObligations::Yes
|
||||||
.iter()
|
}
|
||||||
.find(|obligation| {
|
} else {
|
||||||
|
for obligation in obligations {
|
||||||
// We use `evaluate_root_obligation` to correctly track intercrate
|
// We use `evaluate_root_obligation` to correctly track intercrate
|
||||||
// ambiguity clauses. We cannot use this in the new solver.
|
// ambiguity clauses.
|
||||||
let evaluation_result = selcx.evaluate_root_obligation(obligation);
|
let evaluation_result = selcx.evaluate_root_obligation(obligation);
|
||||||
|
|
||||||
match evaluation_result {
|
match evaluation_result {
|
||||||
Ok(result) => !result.may_apply(),
|
Ok(result) => {
|
||||||
|
if !result.may_apply() {
|
||||||
|
return IntersectionHasImpossibleObligations::Yes;
|
||||||
|
}
|
||||||
|
}
|
||||||
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
|
// 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
|
// 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
|
// 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>),
|
// 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
|
Err(_overflow) => {}
|
||||||
// *must* be treated as ambiguity for completeness.
|
|
||||||
Err(_overflow) => false,
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.cloned()
|
|
||||||
|
IntersectionHasImpossibleObligations::No { overflowing_predicates: Vec::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,9 @@ use crate::traits::{
|
||||||
SelectionError, SignatureMismatch, TraitNotObjectSafe,
|
SelectionError, SignatureMismatch, TraitNotObjectSafe,
|
||||||
};
|
};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||||
use rustc_errors::{
|
use rustc_errors::codes::*;
|
||||||
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
|
use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
|
||||||
MultiSpan, StashKey, StringPart,
|
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey};
|
||||||
};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Namespace, Res};
|
use rustc_hir::def::{DefKind, Namespace, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -62,6 +61,22 @@ pub enum OverflowCause<'tcx> {
|
||||||
TraitSolver(ty::Predicate<'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>)]
|
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
|
||||||
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
fn report_fulfillment_errors(
|
fn report_fulfillment_errors(
|
||||||
|
@ -263,7 +278,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if suggest_increasing_limit {
|
if suggest_increasing_limit {
|
||||||
self.suggest_new_overflow_limit(&mut err);
|
suggest_new_overflow_limit(self.tcx, &mut err);
|
||||||
}
|
}
|
||||||
|
|
||||||
err
|
err
|
||||||
|
@ -303,19 +318,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
/// Reports that a cycle was detected which led to overflow and halts
|
||||||
/// compilation. This is equivalent to `report_overflow_obligation` except
|
/// compilation. This is equivalent to `report_overflow_obligation` except
|
||||||
/// that we can give a more helpful error message (and, in particular,
|
/// that we can give a more helpful error message (and, in particular,
|
||||||
|
@ -335,12 +337,16 @@ impl<'tcx> TypeErrCtxt<'_, '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 obligation = self.resolve_vars_if_possible(obligation);
|
||||||
let mut err = self.build_overflow_error(
|
let mut err = self.build_overflow_error(
|
||||||
OverflowCause::TraitSolver(obligation.predicate),
|
OverflowCause::TraitSolver(obligation.predicate),
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
true,
|
suggest_increasing_limit,
|
||||||
);
|
);
|
||||||
self.note_obligation_cause(&mut err, &obligation);
|
self.note_obligation_cause(&mut err, &obligation);
|
||||||
self.point_at_returns_when_relevant(&mut err, &obligation);
|
self.point_at_returns_when_relevant(&mut err, &obligation);
|
||||||
|
@ -1422,11 +1428,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
FulfillmentErrorCode::ProjectionError(ref e) => {
|
FulfillmentErrorCode::ProjectionError(ref e) => {
|
||||||
self.report_projection_error(&error.obligation, e)
|
self.report_projection_error(&error.obligation, e)
|
||||||
}
|
}
|
||||||
FulfillmentErrorCode::Ambiguity { overflow: false } => {
|
FulfillmentErrorCode::Ambiguity { overflow: None } => {
|
||||||
self.maybe_report_ambiguity(&error.obligation)
|
self.maybe_report_ambiguity(&error.obligation)
|
||||||
}
|
}
|
||||||
FulfillmentErrorCode::Ambiguity { overflow: true } => {
|
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
|
||||||
self.report_overflow_no_abort(error.obligation.clone())
|
self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
|
||||||
}
|
}
|
||||||
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
|
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
|
||||||
.report_mismatched_types(
|
.report_mismatched_types(
|
||||||
|
@ -1910,6 +1916,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
|
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if cand.references_error() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
err.highlighted_help(vec![
|
err.highlighted_help(vec![
|
||||||
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
|
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
|
||||||
StringPart::highlighted("is"),
|
StringPart::highlighted("is"),
|
||||||
|
@ -1934,7 +1943,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let other = if other { "other " } else { "" };
|
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() {
|
if candidates.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||||
_infcx: &InferCtxt<'tcx>,
|
_infcx: &InferCtxt<'tcx>,
|
||||||
) -> Vec<FulfillmentError<'tcx>> {
|
) -> Vec<FulfillmentError<'tcx>> {
|
||||||
self.predicates
|
self.predicates
|
||||||
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: false })
|
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: None })
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(to_fulfillment_error)
|
.map(to_fulfillment_error)
|
||||||
.collect()
|
.collect()
|
||||||
|
|
|
@ -39,6 +39,7 @@ pub struct OverlapError<'tcx> {
|
||||||
pub self_ty: Option<Ty<'tcx>>,
|
pub self_ty: Option<Ty<'tcx>>,
|
||||||
pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
|
pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
|
||||||
pub involves_placeholder: bool,
|
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
|
/// Given the generic parameters for the requested impl, translate it to the generic parameters
|
||||||
|
@ -435,6 +436,14 @@ fn report_conflicting_impls<'tcx>(
|
||||||
if overlap.involves_placeholder {
|
if overlap.involves_placeholder {
|
||||||
coherence::add_placeholder_note(err);
|
coherence::add_placeholder_note(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !overlap.overflowing_predicates.is_empty() {
|
||||||
|
coherence::suggest_increasing_recursion_limit(
|
||||||
|
tcx,
|
||||||
|
err,
|
||||||
|
&overlap.overflowing_predicates,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = DelayDm(|| {
|
let msg = DelayDm(|| {
|
||||||
|
|
|
@ -103,6 +103,7 @@ impl<'tcx> Children {
|
||||||
self_ty: self_ty.has_concrete_skeleton().then_some(self_ty),
|
self_ty: self_ty.has_concrete_skeleton().then_some(self_ty),
|
||||||
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
|
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
|
||||||
involves_placeholder: overlap.involves_placeholder,
|
involves_placeholder: overlap.involves_placeholder,
|
||||||
|
overflowing_predicates: overlap.overflowing_predicates,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
use crate::compiler_interface::with;
|
use crate::compiler_interface::with;
|
||||||
|
use crate::error;
|
||||||
use crate::mir::FieldIdx;
|
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 crate::Opaque;
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
|
@ -100,7 +104,7 @@ impl LayoutShape {
|
||||||
|
|
||||||
/// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
|
/// 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 {
|
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 @@ impl ValueAbi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We currently do not support `Scalar`, and use opaque instead.
|
/// Information about one scalar component of a Rust type.
|
||||||
type Scalar = Opaque;
|
#[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.
|
/// General language calling conventions.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -5,13 +5,15 @@
|
||||||
//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
|
//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
|
||||||
|
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::{error, fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
macro_rules! error {
|
macro_rules! error {
|
||||||
($fmt: literal $(,)?) => { Error(format!($fmt)) };
|
($fmt: literal $(,)?) => { Error(format!($fmt)) };
|
||||||
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
|
($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.
|
/// An error type used to represent an error that has already been reported by the compiler.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum CompilerError<T> {
|
pub enum CompilerError<T> {
|
||||||
|
@ -72,8 +74,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {}
|
impl std::error::Error for Error {}
|
||||||
impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
|
|
||||||
|
impl<T> std::error::Error for CompilerError<T> where T: Display + Debug {}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(value: io::Error) -> Self {
|
fn from(value: io::Error) -> Self {
|
||||||
|
|
|
@ -30,21 +30,29 @@ pub enum Endian {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represent the size of a component.
|
/// 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 {
|
pub struct MachineSize {
|
||||||
num_bits: usize,
|
num_bits: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineSize {
|
impl MachineSize {
|
||||||
|
#[inline(always)]
|
||||||
pub fn bytes(self) -> usize {
|
pub fn bytes(self) -> usize {
|
||||||
self.num_bits / 8
|
self.num_bits / 8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn bits(self) -> usize {
|
pub fn bits(self) -> usize {
|
||||||
self.num_bits
|
self.num_bits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn from_bits(num_bits: usize) -> MachineSize {
|
pub fn from_bits(num_bits: usize) -> MachineSize {
|
||||||
MachineSize { num_bits }
|
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 @@ impl TyKind {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_cstr(&self) -> bool {
|
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))
|
with(|cx| cx.adt_is_cstr(*def))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,10 +1034,13 @@ pub struct BoundTy {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Bytes = Vec<Option<u8>>;
|
pub type Bytes = Vec<Option<u8>>;
|
||||||
|
|
||||||
|
/// Size in bytes.
|
||||||
pub type Size = usize;
|
pub type Size = usize;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
pub struct Prov(pub AllocId);
|
pub struct Prov(pub AllocId);
|
||||||
|
|
||||||
pub type Align = u64;
|
pub type Align = u64;
|
||||||
pub type Promoted = u32;
|
pub type Promoted = u32;
|
||||||
pub type InitMaskMaterialized = Vec<u64>;
|
pub type InitMaskMaterialized = Vec<u64>;
|
||||||
|
|
|
@ -2519,7 +2519,7 @@ impl<T> [T] {
|
||||||
cmp::SliceContains::slice_contains(x, self)
|
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
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -2527,6 +2527,7 @@ impl<T> [T] {
|
||||||
/// let v = [10, 40, 30];
|
/// let v = [10, 40, 30];
|
||||||
/// assert!(v.starts_with(&[10]));
|
/// assert!(v.starts_with(&[10]));
|
||||||
/// assert!(v.starts_with(&[10, 40]));
|
/// assert!(v.starts_with(&[10, 40]));
|
||||||
|
/// assert!(v.starts_with(&v));
|
||||||
/// assert!(!v.starts_with(&[50]));
|
/// assert!(!v.starts_with(&[50]));
|
||||||
/// assert!(!v.starts_with(&[10, 50]));
|
/// assert!(!v.starts_with(&[10, 50]));
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -2549,7 +2550,7 @@ impl<T> [T] {
|
||||||
self.len() >= n && needle == &self[..n]
|
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
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -2557,6 +2558,7 @@ impl<T> [T] {
|
||||||
/// let v = [10, 40, 30];
|
/// let v = [10, 40, 30];
|
||||||
/// assert!(v.ends_with(&[30]));
|
/// assert!(v.ends_with(&[30]));
|
||||||
/// assert!(v.ends_with(&[40, 30]));
|
/// assert!(v.ends_with(&[40, 30]));
|
||||||
|
/// assert!(v.ends_with(&v));
|
||||||
/// assert!(!v.ends_with(&[50]));
|
/// assert!(!v.ends_with(&[50]));
|
||||||
/// assert!(!v.ends_with(&[50, 30]));
|
/// assert!(!v.ends_with(&[50, 30]));
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -2582,7 +2584,8 @@ impl<T> [T] {
|
||||||
/// Returns a subslice with the prefix removed.
|
/// Returns a subslice with the prefix removed.
|
||||||
///
|
///
|
||||||
/// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`.
|
/// 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`.
|
/// If the slice does not start with `prefix`, returns `None`.
|
||||||
///
|
///
|
||||||
|
@ -2592,6 +2595,7 @@ impl<T> [T] {
|
||||||
/// let v = &[10, 40, 30];
|
/// let v = &[10, 40, 30];
|
||||||
/// assert_eq!(v.strip_prefix(&[10]), Some(&[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]), Some(&[30][..]));
|
||||||
|
/// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..]));
|
||||||
/// assert_eq!(v.strip_prefix(&[50]), None);
|
/// assert_eq!(v.strip_prefix(&[50]), None);
|
||||||
/// assert_eq!(v.strip_prefix(&[10, 50]), None);
|
/// assert_eq!(v.strip_prefix(&[10, 50]), None);
|
||||||
///
|
///
|
||||||
|
@ -2620,7 +2624,8 @@ impl<T> [T] {
|
||||||
/// Returns a subslice with the suffix removed.
|
/// Returns a subslice with the suffix removed.
|
||||||
///
|
///
|
||||||
/// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`.
|
/// 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`.
|
/// If the slice does not end with `suffix`, returns `None`.
|
||||||
///
|
///
|
||||||
|
@ -2630,6 +2635,7 @@ impl<T> [T] {
|
||||||
/// let v = &[10, 40, 30];
|
/// let v = &[10, 40, 30];
|
||||||
/// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
|
/// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
|
||||||
/// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..]));
|
/// 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]), None);
|
||||||
/// assert_eq!(v.strip_suffix(&[50, 30]), None);
|
/// assert_eq!(v.strip_suffix(&[50, 30]), None);
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -26,6 +26,7 @@ fn main() {
|
||||||
"InstrProfilingMerge.c",
|
"InstrProfilingMerge.c",
|
||||||
"InstrProfilingMergeFile.c",
|
"InstrProfilingMergeFile.c",
|
||||||
"InstrProfilingNameVar.c",
|
"InstrProfilingNameVar.c",
|
||||||
|
"InstrProfilingPlatformAIX.c",
|
||||||
"InstrProfilingPlatformDarwin.c",
|
"InstrProfilingPlatformDarwin.c",
|
||||||
"InstrProfilingPlatformFuchsia.c",
|
"InstrProfilingPlatformFuchsia.c",
|
||||||
"InstrProfilingPlatformLinux.c",
|
"InstrProfilingPlatformLinux.c",
|
||||||
|
|
|
@ -19,12 +19,10 @@ struct FooDefault<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct TupleDefault(bool, i32, u64);
|
struct TupleDefault(bool, i32, u64);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct FooND1 {
|
struct FooND1 {
|
||||||
a: bool,
|
a: bool,
|
||||||
}
|
}
|
||||||
|
@ -73,7 +71,6 @@ impl Default for FooNDVec {
|
||||||
struct StrDefault<'a>(&'a str);
|
struct StrDefault<'a>(&'a str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct AlreadyDerived(i32, bool);
|
struct AlreadyDerived(i32, bool);
|
||||||
|
|
||||||
|
@ -96,7 +93,6 @@ mac!(0);
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Y(u32);
|
struct Y(u32);
|
||||||
|
|
||||||
|
|
||||||
struct RustIssue26925<T> {
|
struct RustIssue26925<T> {
|
||||||
a: Option<T>,
|
a: Option<T>,
|
||||||
}
|
}
|
||||||
|
@ -132,12 +128,10 @@ struct WithoutSelfCurly {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct WithoutSelfParan(bool);
|
struct WithoutSelfParan(bool);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// https://github.com/rust-lang/rust-clippy/issues/7655
|
// https://github.com/rust-lang/rust-clippy/issues/7655
|
||||||
|
|
||||||
pub struct SpecializedImpl2<T> {
|
pub struct SpecializedImpl2<T> {
|
||||||
|
@ -184,7 +178,6 @@ pub struct RepeatDefault1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub struct RepeatDefault2 {
|
pub struct RepeatDefault2 {
|
||||||
a: [i8; 33],
|
a: [i8; 33],
|
||||||
}
|
}
|
||||||
|
@ -216,7 +209,6 @@ pub enum SimpleEnum {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub enum NonExhaustiveEnum {
|
pub enum NonExhaustiveEnum {
|
||||||
Foo,
|
Foo,
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// shouldn't cause an error
|
// shouldn't cause an error
|
||||||
struct Bar;
|
struct Bar;
|
||||||
|
|
||||||
|
@ -19,5 +18,4 @@ impl Drop for Bar {
|
||||||
struct Baz;
|
struct Baz;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -6,13 +6,10 @@
|
||||||
extern crate proc_macros;
|
extern crate proc_macros;
|
||||||
use proc_macros::external;
|
use proc_macros::external;
|
||||||
|
|
||||||
|
|
||||||
pub fn must_use_default() {}
|
pub fn must_use_default() {}
|
||||||
|
|
||||||
|
|
||||||
pub fn must_use_unit() -> () {}
|
pub fn must_use_unit() -> () {}
|
||||||
|
|
||||||
|
|
||||||
pub fn must_use_with_note() {}
|
pub fn must_use_with_note() {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
use core;
|
use core;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
use serde as edres;
|
use serde as edres;
|
||||||
|
|
||||||
pub use serde;
|
pub use serde;
|
||||||
|
|
|
@ -3797,9 +3797,9 @@
|
||||||
"ui/rust-2018/uniform-paths/issue-56596-2.rs",
|
"ui/rust-2018/uniform-paths/issue-56596-2.rs",
|
||||||
"ui/rust-2018/uniform-paths/issue-56596.rs",
|
"ui/rust-2018/uniform-paths/issue-56596.rs",
|
||||||
"ui/rust-2018/uniform-paths/issue-87932.rs",
|
"ui/rust-2018/uniform-paths/issue-87932.rs",
|
||||||
"ui/sanitize/issue-111184-coroutine-witness.rs",
|
"ui/sanitizer/issue-111184-cfi-coroutine-witness.rs",
|
||||||
"ui/sanitize/issue-114275-cfi-const-expr-in-arry-len.rs",
|
"ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs",
|
||||||
"ui/sanitize/issue-72154-lifetime-markers.rs",
|
"ui/sanitizer/issue-72154-address-lifetime-markers.rs",
|
||||||
"ui/self/issue-61882-2.rs",
|
"ui/self/issue-61882-2.rs",
|
||||||
"ui/self/issue-61882.rs",
|
"ui/self/issue-61882.rs",
|
||||||
"ui/simd/intrinsic/issue-85855.rs",
|
"ui/simd/intrinsic/issue-85855.rs",
|
||||||
|
|
|
@ -42,15 +42,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
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];
|
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
- falseEdge -> [real: bb20, imaginary: bb4];
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- bb4: {
|
|
||||||
StorageLive(_15);
|
StorageLive(_15);
|
||||||
_15 = (_2.1: bool);
|
_15 = (_2.1: bool);
|
||||||
StorageLive(_16);
|
StorageLive(_16);
|
||||||
|
@ -59,8 +55,12 @@
|
||||||
+ goto -> bb16;
|
+ goto -> bb16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
- falseEdge -> [real: bb20, imaginary: bb3];
|
||||||
|
- }
|
||||||
|
-
|
||||||
- bb5: {
|
- bb5: {
|
||||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
- falseEdge -> [real: bb13, imaginary: bb4];
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb6: {
|
- bb6: {
|
||||||
|
@ -68,7 +68,6 @@
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb7: {
|
- bb7: {
|
||||||
+ bb4: {
|
|
||||||
_0 = const 1_i32;
|
_0 = const 1_i32;
|
||||||
- drop(_7) -> [return: bb18, unwind: bb25];
|
- drop(_7) -> [return: bb18, unwind: bb25];
|
||||||
+ drop(_7) -> [return: bb15, unwind: bb22];
|
+ drop(_7) -> [return: bb15, unwind: bb22];
|
||||||
|
@ -184,7 +183,7 @@
|
||||||
StorageDead(_12);
|
StorageDead(_12);
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
- falseEdge -> [real: bb2, imaginary: bb4];
|
||||||
+ goto -> bb2;
|
+ goto -> bb2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,15 +42,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
bb2: {
|
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];
|
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb3: {
|
bb3: {
|
||||||
- falseEdge -> [real: bb20, imaginary: bb4];
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- bb4: {
|
|
||||||
StorageLive(_15);
|
StorageLive(_15);
|
||||||
_15 = (_2.1: bool);
|
_15 = (_2.1: bool);
|
||||||
StorageLive(_16);
|
StorageLive(_16);
|
||||||
|
@ -59,8 +55,12 @@
|
||||||
+ goto -> bb16;
|
+ goto -> bb16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
- falseEdge -> [real: bb20, imaginary: bb3];
|
||||||
|
- }
|
||||||
|
-
|
||||||
- bb5: {
|
- bb5: {
|
||||||
- falseEdge -> [real: bb13, imaginary: bb3];
|
- falseEdge -> [real: bb13, imaginary: bb4];
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb6: {
|
- bb6: {
|
||||||
|
@ -68,7 +68,6 @@
|
||||||
- }
|
- }
|
||||||
-
|
-
|
||||||
- bb7: {
|
- bb7: {
|
||||||
+ bb4: {
|
|
||||||
_0 = const 1_i32;
|
_0 = const 1_i32;
|
||||||
- drop(_7) -> [return: bb18, unwind: bb25];
|
- drop(_7) -> [return: bb18, unwind: bb25];
|
||||||
+ drop(_7) -> [return: bb15, unwind: bb22];
|
+ drop(_7) -> [return: bb15, unwind: bb22];
|
||||||
|
@ -184,7 +183,7 @@
|
||||||
StorageDead(_12);
|
StorageDead(_12);
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
- falseEdge -> [real: bb2, imaginary: bb3];
|
- falseEdge -> [real: bb2, imaginary: bb4];
|
||||||
+ goto -> bb2;
|
+ goto -> bb2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
//@ check-pass
|
|
||||||
|
|
||||||
#[doc(include = "external-cross-doc.md")]
|
#[doc(include = "external-cross-doc.md")]
|
||||||
//~^ WARNING unknown `doc` attribute `include`
|
//~^ ERROR unknown `doc` attribute `include`
|
||||||
//~| HELP use `doc = include_str!` instead
|
//~| HELP use `doc = include_str!` instead
|
||||||
// FIXME(#85497): make this a deny instead so it's more clear what's happening
|
// FIXME(#85497): make this a deny instead so it's more clear what's happening
|
||||||
//~| NOTE on by default
|
//~| NOTE on by default
|
||||||
//~| WARNING previously accepted
|
|
||||||
//~| NOTE see issue #82730
|
|
||||||
pub struct NeedMoreDocs;
|
pub struct NeedMoreDocs;
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
warning: unknown `doc` attribute `include`
|
error: unknown `doc` attribute `include`
|
||||||
--> $DIR/doc-include-suggestion.rs:3:7
|
--> $DIR/doc-include-suggestion.rs:1:7
|
||||||
|
|
|
|
||||||
LL | #[doc(include = "external-cross-doc.md")]
|
LL | #[doc(include = "external-cross-doc.md")]
|
||||||
| ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("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: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
|
||||||
= note: `#[warn(invalid_doc_attributes)]` on by default
|
|
||||||
|
|
||||||
warning: 1 warning emitted
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![deny(invalid_doc_attributes)]
|
|
||||||
|
|
||||||
#![doc(test)]
|
#![doc(test)]
|
||||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||||
//~^^ WARN this was previously accepted by the compiler
|
|
||||||
#![doc(test = "hello")]
|
#![doc(test = "hello")]
|
||||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||||
//~^^ WARN this was previously accepted by the compiler
|
|
||||||
#![doc(test(a))]
|
#![doc(test(a))]
|
||||||
//~^ ERROR unknown `doc(test)` attribute `a`
|
//~^ ERROR unknown `doc(test)` attribute `a`
|
||||||
//~^^ WARN this was previously accepted by the compiler
|
|
||||||
|
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
|
@ -1,34 +1,22 @@
|
||||||
error: `#[doc(test(...)]` takes a list of attributes
|
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)]
|
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: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
= 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)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: `#[doc(test(...)]` takes a list of attributes
|
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")]
|
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`
|
error: unknown `doc(test)` attribute `a`
|
||||||
--> $DIR/doc-test-attr.rs:10:13
|
--> $DIR/doc-test-attr.rs:7:13
|
||||||
|
|
|
|
||||||
LL | #![doc(test(a))]
|
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
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,17 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![deny(warnings)]
|
|
||||||
#![doc(as_ptr)]
|
#![doc(as_ptr)]
|
||||||
//~^ ERROR unknown `doc` attribute
|
//~^ ERROR unknown `doc` attribute
|
||||||
//~^^ WARN
|
|
||||||
|
|
||||||
#[doc(as_ptr)]
|
#[doc(as_ptr)]
|
||||||
//~^ ERROR unknown `doc` attribute
|
//~^ ERROR unknown `doc` attribute
|
||||||
//~^^ WARN
|
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
||||||
#[doc(123)]
|
#[doc(123)]
|
||||||
//~^ ERROR invalid `doc` attribute
|
//~^ ERROR invalid `doc` attribute
|
||||||
//~| WARN
|
|
||||||
#[doc("hello", "bar")]
|
#[doc("hello", "bar")]
|
||||||
//~^ ERROR invalid `doc` attribute
|
//~^ ERROR invalid `doc` attribute
|
||||||
//~| WARN
|
|
||||||
//~| ERROR invalid `doc` attribute
|
//~| ERROR invalid `doc` attribute
|
||||||
//~| WARN
|
|
||||||
#[doc(foo::bar, crate::bar::baz = "bye")]
|
#[doc(foo::bar, crate::bar::baz = "bye")]
|
||||||
//~^ ERROR unknown `doc` attribute
|
//~^ ERROR unknown `doc` attribute
|
||||||
//~| WARN
|
|
||||||
//~| ERROR unknown `doc` attribute
|
//~| ERROR unknown `doc` attribute
|
||||||
//~| WARN
|
|
||||||
fn bar() {}
|
fn bar() {}
|
||||||
|
|
|
@ -1,71 +1,46 @@
|
||||||
error: unknown `doc` attribute `as_ptr`
|
error: unknown `doc` attribute `as_ptr`
|
||||||
--> $DIR/doc-attr.rs:7:7
|
--> $DIR/doc-attr.rs:5:7
|
||||||
|
|
|
|
||||||
LL | #[doc(as_ptr)]
|
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: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
= 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)]`
|
|
||||||
|
|
||||||
error: invalid `doc` attribute
|
error: invalid `doc` attribute
|
||||||
--> $DIR/doc-attr.rs:12:7
|
--> $DIR/doc-attr.rs:9:7
|
||||||
|
|
|
|
||||||
LL | #[doc(123)]
|
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
|
error: invalid `doc` attribute
|
||||||
--> $DIR/doc-attr.rs:15:7
|
--> $DIR/doc-attr.rs:11:7
|
||||||
|
|
|
|
||||||
LL | #[doc("hello", "bar")]
|
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
|
error: invalid `doc` attribute
|
||||||
--> $DIR/doc-attr.rs:15:16
|
--> $DIR/doc-attr.rs:11:16
|
||||||
|
|
|
|
||||||
LL | #[doc("hello", "bar")]
|
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`
|
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")]
|
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`
|
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")]
|
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`
|
error: unknown `doc` attribute `as_ptr`
|
||||||
--> $DIR/doc-attr.rs:3:8
|
--> $DIR/doc-attr.rs:2:8
|
||||||
|
|
|
|
||||||
LL | #![doc(as_ptr)]
|
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
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
#![deny(warnings)]
|
|
||||||
#![feature(doc_notable_trait)]
|
#![feature(doc_notable_trait)]
|
||||||
|
|
||||||
#[doc(notable_trait)]
|
#[doc(notable_trait)]
|
||||||
//~^ ERROR unknown `doc` attribute `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 {}
|
trait MyTrait {}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
#![deny(warnings)]
|
|
||||||
#![feature(doc_notable_trait)]
|
#![feature(doc_notable_trait)]
|
||||||
|
|
||||||
#[doc(spotlight)]
|
#[doc(spotlight)]
|
||||||
//~^ ERROR unknown `doc` attribute `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 {}
|
trait MyTrait {}
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
error: unknown `doc` attribute `spotlight`
|
error: unknown `doc` attribute `spotlight`
|
||||||
--> $DIR/doc-spotlight.rs:5:7
|
--> $DIR/doc-spotlight.rs:4:7
|
||||||
|
|
|
|
||||||
LL | #[doc(spotlight)]
|
LL | #[doc(spotlight)]
|
||||||
| ^^^^^^^^^ help: use `notable_trait` instead
|
| ^^^^^^^^^ 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)` was renamed to `doc(notable_trait)`
|
||||||
= note: `doc(spotlight)` is now a no-op
|
= note: `doc(spotlight)` is now a no-op
|
||||||
note: the lint level is defined here
|
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
--> $DIR/doc-spotlight.rs:2:9
|
|
||||||
|
|
|
||||||
LL | #![deny(warnings)]
|
|
||||||
| ^^^^^^^^
|
|
||||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
#![feature(doc_cfg_hide)]
|
#![feature(doc_cfg_hide)]
|
||||||
#![deny(warnings)]
|
|
||||||
|
|
||||||
#![doc(cfg_hide = "test")] //~ ERROR
|
#![doc(cfg_hide = "test")] //~ ERROR
|
||||||
//~^ WARN
|
|
||||||
#![doc(cfg_hide)] //~ ERROR
|
#![doc(cfg_hide)] //~ ERROR
|
||||||
//~^ WARN
|
|
||||||
|
|
||||||
#[doc(cfg_hide(doc))] //~ ERROR
|
#[doc(cfg_hide(doc))] //~ ERROR
|
||||||
//~^ WARN
|
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
|
@ -1,40 +1,27 @@
|
||||||
error: this attribute can only be applied at the crate level
|
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))]
|
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: 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
|
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
--> $DIR/doc_cfg_hide.rs:2:9
|
|
||||||
|
|
|
||||||
LL | #![deny(warnings)]
|
|
||||||
| ^^^^^^^^
|
|
||||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
|
||||||
help: to apply to the crate, use an inner attribute
|
help: to apply to the crate, use an inner attribute
|
||||||
|
|
|
|
||||||
LL | #![doc(cfg_hide(doc))]
|
LL | #![doc(cfg_hide(doc))]
|
||||||
| +
|
| +
|
||||||
|
|
||||||
error: `#[doc(cfg_hide(...))]` takes a list of attributes
|
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")]
|
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
|
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)]
|
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
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,25 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![deny(warnings)]
|
|
||||||
#![feature(doc_masked)]
|
#![feature(doc_masked)]
|
||||||
|
|
||||||
#![doc(masked)]
|
#![doc(masked)]
|
||||||
//~^ ERROR this attribute can only be applied to an `extern crate` item
|
//~^ ERROR this attribute can only be applied to an `extern crate` item
|
||||||
//~| WARN is being phased out
|
|
||||||
|
|
||||||
#[doc(test(no_crate_inject))]
|
#[doc(test(no_crate_inject))]
|
||||||
//~^ ERROR can only be applied at the crate level
|
//~^ ERROR can only be applied at the crate level
|
||||||
//~| WARN is being phased out
|
|
||||||
//~| HELP to apply to the crate, use an inner attribute
|
//~| HELP to apply to the crate, use an inner attribute
|
||||||
//~| SUGGESTION !
|
//~| SUGGESTION !
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
//~^ ERROR can only be applied to a `use` item
|
//~^ ERROR can only be applied to a `use` item
|
||||||
//~| WARN is being phased out
|
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
||||||
pub mod bar {
|
pub mod bar {
|
||||||
#![doc(test(no_crate_inject))]
|
#![doc(test(no_crate_inject))]
|
||||||
//~^ ERROR can only be applied at the crate level
|
//~^ ERROR can only be applied at the crate level
|
||||||
//~| WARN is being phased out
|
|
||||||
|
|
||||||
#[doc(test(no_crate_inject))]
|
#[doc(test(no_crate_inject))]
|
||||||
//~^ ERROR can only be applied at the crate level
|
//~^ ERROR can only be applied at the crate level
|
||||||
//~| WARN is being phased out
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
//~^ ERROR can only be applied to a `use` item
|
//~^ ERROR can only be applied to a `use` item
|
||||||
//~| WARN is being phased out
|
|
||||||
pub fn baz() {}
|
pub fn baz() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +31,8 @@ pub use bar::baz;
|
||||||
|
|
||||||
#[doc(masked)]
|
#[doc(masked)]
|
||||||
//~^ ERROR this attribute can only be applied to an `extern crate` item
|
//~^ ERROR this attribute can only be applied to an `extern crate` item
|
||||||
//~| WARN is being phased out
|
|
||||||
pub struct Masked;
|
pub struct Masked;
|
||||||
|
|
||||||
#[doc(masked)]
|
#[doc(masked)]
|
||||||
//~^ ERROR this attribute cannot be applied to an `extern crate self` item
|
//~^ ERROR this attribute cannot be applied to an `extern crate self` item
|
||||||
//~| WARN is being phased out
|
|
||||||
pub extern crate self as reexport;
|
pub extern crate self as reexport;
|
||||||
|
|
|
@ -1,48 +1,37 @@
|
||||||
error: this attribute can only be applied at the crate level
|
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))]
|
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: 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
|
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
--> $DIR/invalid-doc-attr.rs:2:9
|
|
||||||
|
|
|
||||||
LL | #![deny(warnings)]
|
|
||||||
| ^^^^^^^^
|
|
||||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
|
|
||||||
help: to apply to the crate, use an inner attribute
|
help: to apply to the crate, use an inner attribute
|
||||||
|
|
|
|
||||||
LL | #![doc(test(no_crate_inject))]
|
LL | #![doc(test(no_crate_inject))]
|
||||||
| +
|
| +
|
||||||
|
|
||||||
error: this attribute can only be applied to a `use` item
|
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)]
|
LL | #[doc(inline)]
|
||||||
| ^^^^^^ only applicable on `use` items
|
| ^^^^^^ only applicable on `use` items
|
||||||
...
|
LL |
|
||||||
LL | pub fn foo() {}
|
LL | pub fn foo() {}
|
||||||
| ------------ not a `use` item
|
| ------------ 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
|
= 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
|
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))]
|
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: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||||
|
|
||||||
error: conflicting doc inlining attributes
|
error: conflicting doc inlining attributes
|
||||||
--> $DIR/invalid-doc-attr.rs:33:7
|
--> $DIR/invalid-doc-attr.rs:26:7
|
||||||
|
|
|
|
||||||
LL | #[doc(inline)]
|
LL | #[doc(inline)]
|
||||||
| ^^^^^^ this attribute...
|
| ^^^^^^ this attribute...
|
||||||
|
@ -52,61 +41,50 @@ LL | #[doc(no_inline)]
|
||||||
= help: remove one of the conflicting attributes
|
= help: remove one of the conflicting attributes
|
||||||
|
|
||||||
error: this attribute can only be applied to an `extern crate` item
|
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)]
|
LL | #[doc(masked)]
|
||||||
| ^^^^^^ only applicable on `extern crate` items
|
| ^^^^^^ only applicable on `extern crate` items
|
||||||
...
|
LL |
|
||||||
LL | pub struct Masked;
|
LL | pub struct Masked;
|
||||||
| ----------------- not an `extern crate` item
|
| ----------------- 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
|
= 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
|
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)]
|
LL | #[doc(masked)]
|
||||||
| ^^^^^^ not applicable on `extern crate self` items
|
| ^^^^^^ not applicable on `extern crate self` items
|
||||||
...
|
LL |
|
||||||
LL | pub extern crate self as reexport;
|
LL | pub extern crate self as reexport;
|
||||||
| --------------------------------- `extern crate self` defined here
|
| --------------------------------- `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
|
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)]
|
LL | #![doc(masked)]
|
||||||
| ^^^^^^ only applicable on `extern crate` items
|
| ^^^^^^ 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
|
= 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
|
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))]
|
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: 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
|
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)]
|
LL | #[doc(inline)]
|
||||||
| ^^^^^^ only applicable on `use` items
|
| ^^^^^^ only applicable on `use` items
|
||||||
...
|
LL |
|
||||||
LL | pub fn baz() {}
|
LL | pub fn baz() {}
|
||||||
| ------------ not a `use` item
|
| ------------ 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
|
= 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
|
error: aborting due to 9 previous errors
|
||||||
|
|
|
@ -19,8 +19,12 @@ extern crate rustc_interface;
|
||||||
extern crate stable_mir;
|
extern crate stable_mir;
|
||||||
|
|
||||||
use rustc_smir::rustc_internal;
|
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::mir::mono::Instance;
|
||||||
|
use stable_mir::target::MachineInfo;
|
||||||
use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
|
use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
|
||||||
use std::assert_matches::assert_matches;
|
use std::assert_matches::assert_matches;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
@ -39,11 +43,12 @@ fn test_stable_mir() -> ControlFlow<()> {
|
||||||
let instance = Instance::try_from(target_fn).unwrap();
|
let instance = Instance::try_from(target_fn).unwrap();
|
||||||
let fn_abi = instance.fn_abi().unwrap();
|
let fn_abi = instance.fn_abi().unwrap();
|
||||||
assert_eq!(fn_abi.conv, CallConvention::Rust);
|
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_ignore(&fn_abi.args[0]);
|
||||||
check_primitive(&fn_abi.args[1]);
|
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.
|
// Test variadic function.
|
||||||
let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
|
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>`.
|
/// Check the return value: `Result<usize, &str>`.
|
||||||
fn check_result(abi: ArgAbi) {
|
fn check_result(abi: &ArgAbi) {
|
||||||
assert!(abi.ty.kind().is_enum());
|
assert!(abi.ty.kind().is_enum());
|
||||||
assert_matches!(abi.mode, PassMode::Indirect { .. });
|
assert_matches!(abi.mode, PassMode::Indirect { .. });
|
||||||
let layout = abi.layout.shape();
|
let layout = abi.layout.shape();
|
||||||
|
@ -94,6 +99,25 @@ fn check_result(abi: ArgAbi) {
|
||||||
assert_matches!(layout.variants, VariantsShape::Multiple { .. })
|
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>(
|
fn get_item<'a>(
|
||||||
items: &'a CrateItems,
|
items: &'a CrateItems,
|
||||||
item: (ItemKind, &str),
|
item: (ItemKind, &str),
|
||||||
|
@ -126,12 +150,17 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
||||||
#![feature(c_variadic)]
|
#![feature(c_variadic)]
|
||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
|
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.
|
// We only care about the signature.
|
||||||
todo!()
|
todo!()
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
|
||||||
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
|
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
|
||||||
0
|
0
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -55,7 +55,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
|
||||||
LL | foo::<Demo>()();
|
LL | foo::<Demo>()();
|
||||||
| ^^^^ the trait `TraitWAssocConst` is not implemented for `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`
|
note: required by a bound in `foo`
|
||||||
--> $DIR/issue-105330.rs:11:11
|
--> $DIR/issue-105330.rs:11:11
|
||||||
|
|
|
|
||||||
|
@ -92,7 +91,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
|
||||||
LL | foo::<Demo>();
|
LL | foo::<Demo>();
|
||||||
| ^^^^ the trait `TraitWAssocConst` is not implemented for `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`
|
note: required by a bound in `foo`
|
||||||
--> $DIR/issue-105330.rs:11:11
|
--> $DIR/issue-105330.rs:11:11
|
||||||
|
|
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ impl Grault for () {
|
||||||
|
|
||||||
impl<T: Grault> Grault for (T,)
|
impl<T: Grault> Grault for (T,)
|
||||||
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
|
||||||
|
|
||||||
{
|
{
|
||||||
type A = ();
|
type A = ();
|
||||||
type B = bool;
|
type B = bool;
|
||||||
|
|
|
@ -1,25 +1,17 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![deny(warnings)]
|
|
||||||
#![doc(as_ptr)]
|
#![doc(as_ptr)]
|
||||||
//~^ ERROR unknown `doc` attribute
|
//~^ ERROR unknown `doc` attribute
|
||||||
//~^^ WARN
|
|
||||||
|
|
||||||
#[doc(as_ptr)]
|
#[doc(as_ptr)]
|
||||||
//~^ ERROR unknown `doc` attribute
|
//~^ ERROR unknown `doc` attribute
|
||||||
//~^^ WARN
|
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
||||||
#[doc(123)]
|
#[doc(123)]
|
||||||
//~^ ERROR invalid `doc` attribute
|
//~^ ERROR invalid `doc` attribute
|
||||||
//~| WARN
|
|
||||||
#[doc("hello", "bar")]
|
#[doc("hello", "bar")]
|
||||||
//~^ ERROR invalid `doc` attribute
|
//~^ ERROR invalid `doc` attribute
|
||||||
//~| WARN
|
|
||||||
//~| ERROR invalid `doc` attribute
|
//~| ERROR invalid `doc` attribute
|
||||||
//~| WARN
|
|
||||||
#[doc(foo::bar, crate::bar::baz = "bye")]
|
#[doc(foo::bar, crate::bar::baz = "bye")]
|
||||||
//~^ ERROR unknown `doc` attribute
|
//~^ ERROR unknown `doc` attribute
|
||||||
//~| WARN
|
|
||||||
//~| ERROR unknown `doc` attribute
|
//~| ERROR unknown `doc` attribute
|
||||||
//~| WARN
|
|
||||||
fn bar() {}
|
fn bar() {}
|
||||||
|
|
|
@ -1,71 +1,46 @@
|
||||||
error: unknown `doc` attribute `as_ptr`
|
error: unknown `doc` attribute `as_ptr`
|
||||||
--> $DIR/doc-attr.rs:7:7
|
--> $DIR/doc-attr.rs:5:7
|
||||||
|
|
|
|
||||||
LL | #[doc(as_ptr)]
|
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: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
= 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)]`
|
|
||||||
|
|
||||||
error: invalid `doc` attribute
|
error: invalid `doc` attribute
|
||||||
--> $DIR/doc-attr.rs:12:7
|
--> $DIR/doc-attr.rs:9:7
|
||||||
|
|
|
|
||||||
LL | #[doc(123)]
|
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
|
error: invalid `doc` attribute
|
||||||
--> $DIR/doc-attr.rs:15:7
|
--> $DIR/doc-attr.rs:11:7
|
||||||
|
|
|
|
||||||
LL | #[doc("hello", "bar")]
|
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
|
error: invalid `doc` attribute
|
||||||
--> $DIR/doc-attr.rs:15:16
|
--> $DIR/doc-attr.rs:11:16
|
||||||
|
|
|
|
||||||
LL | #[doc("hello", "bar")]
|
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`
|
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")]
|
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`
|
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")]
|
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`
|
error: unknown `doc` attribute `as_ptr`
|
||||||
--> $DIR/doc-attr.rs:3:8
|
--> $DIR/doc-attr.rs:2:8
|
||||||
|
|
|
|
||||||
LL | #![doc(as_ptr)]
|
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
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
#![deny(warnings)]
|
|
||||||
|
|
||||||
#![doc(test(""))]
|
#![doc(test(""))]
|
||||||
//~^ ERROR `#![doc(test(...)]` does not take a literal
|
//~^ 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() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
error: `#![doc(test(...)]` does not take a literal
|
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(""))]
|
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: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
= 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)]`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ pub mod submodule {
|
||||||
// Error since this is a `future_incompatible` lint
|
// Error since this is a `future_incompatible` lint
|
||||||
#![doc(test(some_test))]
|
#![doc(test(some_test))]
|
||||||
//~^ ERROR this attribute can only be applied at the crate level
|
//~^ ERROR this attribute can only be applied at the crate level
|
||||||
//~| WARN this was previously accepted by the compiler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -14,15 +14,8 @@ error: this attribute can only be applied at the crate level
|
||||||
LL | #![doc(test(some_test))]
|
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: 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
|
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
--> $DIR/future-incompatible-lint-group.rs:3:9
|
|
||||||
|
|
|
||||||
LL | #![deny(future_incompatible)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(future_incompatible)]`
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error; 1 warning emitted
|
error: aborting due to 1 previous error; 1 warning emitted
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![deny(no_mangle_generic_items)]
|
#![deny(no_mangle_generic_items)]
|
||||||
|
|
||||||
|
|
||||||
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
|
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
|
pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
|
||||||
|
|
||||||
#[no_mangle]
|
#[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:;
|
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`
|
note: required by a bound in `Bar`
|
||||||
--> $DIR/issue-95230.rs:9:13
|
--> $DIR/issue-95230.rs:9:13
|
||||||
|
|
|
|
||||||
|
|
|
@ -27,10 +27,8 @@ use issue_52891::{l,
|
||||||
use issue_52891::a::inner;
|
use issue_52891::a::inner;
|
||||||
use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times
|
use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times
|
||||||
|
|
||||||
|
|
||||||
//~^ ERROR `issue_52891` is defined multiple times
|
//~^ ERROR `issue_52891` is defined multiple times
|
||||||
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
use issue_52891::n; //~ ERROR `n` is defined multiple times
|
use issue_52891::n; //~ ERROR `n` is defined multiple times
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#![deny(unused_imports)]
|
#![deny(unused_imports)]
|
||||||
|
|
||||||
// Check that attributes get removed too. See #87973.
|
// Check that attributes get removed too. See #87973.
|
||||||
|
|
||||||
//~^ ERROR unused import
|
//~^ ERROR unused import
|
||||||
|
|
||||||
fn main() {}
|
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 {}
|
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
|
error[E0392]: type parameter `T` is never used
|
||||||
--> $DIR/inherent-impls-overflow.rs:13:12
|
--> $DIR/inherent-impls-overflow.rs:13:12
|
||||||
|
|
|
@ -7,11 +7,9 @@
|
||||||
// Check that we *reject* leading where-clauses on lazy type aliases.
|
// Check that we *reject* leading where-clauses on lazy type aliases.
|
||||||
|
|
||||||
pub type Leading0<T>
|
pub type Leading0<T>
|
||||||
|
|
||||||
= T where String: From<T>;
|
= T where String: From<T>;
|
||||||
|
|
||||||
pub type Leading1<T, U>
|
pub type Leading1<T, U>
|
||||||
|
|
||||||
= (T, U)
|
= (T, U)
|
||||||
where
|
where
|
||||||
U: Copy, String: From<T>;
|
U: Copy, String: From<T>;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
//~^ ERROR const items should never be `#[no_mangle]`
|
//~^ ERROR const items should never be `#[no_mangle]`
|
||||||
//~| HELP try a static value
|
//~| HELP try a static value
|
||||||
|
|
||||||
|
|
||||||
//~^ HELP remove this attribute
|
//~^ HELP remove this attribute
|
||||||
pub fn defiant<T>(_t: T) {}
|
pub fn defiant<T>(_t: T) {}
|
||||||
//~^ WARN functions generic over types or consts must be mangled
|
//~^ 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
|
#[repr(uwu)] //~ERROR: unrecognized representation hint
|
||||||
#[doc(owo)] //~WARN: unknown `doc` attribute
|
#[doc(owo)] //~ERROR: unknown `doc` attribute
|
||||||
//~^ WARN: this was previously
|
|
||||||
pub struct Owo5;
|
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`
|
= 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
|
--> $DIR/invalid_repr_list_help.rs:20:7
|
||||||
|
|
|
|
||||||
LL | #[doc(owo)]
|
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: `#[deny(invalid_doc_attributes)]` on by default
|
||||||
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
|
|
||||||
= note: `#[warn(invalid_doc_attributes)]` on by default
|
|
||||||
|
|
||||||
error[E0552]: unrecognized representation hint
|
error[E0552]: unrecognized representation hint
|
||||||
--> $DIR/invalid_repr_list_help.rs:19:8
|
--> $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`
|
= 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`.
|
For more information about this error, try `rustc --explain E0552`.
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
|
|
||||||
//~^ ERROR the name `transmute` is defined multiple times
|
//~^ ERROR the name `transmute` is defined multiple times
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
|
||||||
//~^ ERROR unused extern crate
|
//~^ ERROR unused extern crate
|
||||||
|
|
||||||
// Shouldn't suggest changing to `use`, as `bar`
|
// Shouldn't suggest changing to `use`, as `bar`
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
// The suggestion span should include the attribute.
|
// The suggestion span should include the attribute.
|
||||||
|
|
||||||
|
|
||||||
//~^ ERROR unused extern crate
|
//~^ ERROR unused extern crate
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -2,6 +2,4 @@
|
||||||
//~^ NOTE defined here
|
//~^ NOTE defined here
|
||||||
#![doc(x)]
|
#![doc(x)]
|
||||||
//~^ ERROR unknown `doc` attribute `x`
|
//~^ ERROR unknown `doc` attribute `x`
|
||||||
//~| WARNING will become a hard error
|
|
||||||
//~| NOTE see issue #82730
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,8 +4,6 @@ error: unknown `doc` attribute `x`
|
||||||
LL | #![doc(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
|
note: the lint level is defined here
|
||||||
--> $DIR/deny-invalid-doc-attrs.rs:1:9
|
--> $DIR/deny-invalid-doc-attrs.rs:1:9
|
||||||
|
|
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#[doc(primitive = "foo")]
|
#[doc(primitive = "foo")]
|
||||||
//~^ ERROR unknown `doc` attribute `primitive`
|
//~^ ERROR unknown `doc` attribute `primitive`
|
||||||
//~| WARN
|
|
||||||
mod bar {}
|
mod bar {}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,8 +4,6 @@ error: unknown `doc` attribute `primitive`
|
||||||
LL | #[doc(primitive = "foo")]
|
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
|
note: the lint level is defined here
|
||||||
--> $DIR/doc-primitive.rs:1:9
|
--> $DIR/doc-primitive.rs:1:9
|
||||||
|
|
|
|
||||||
|
|
|
@ -3,12 +3,9 @@
|
||||||
|
|
||||||
#![doc(test)]
|
#![doc(test)]
|
||||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||||
//~^^ WARN this was previously accepted by the compiler
|
|
||||||
#![doc(test = "hello")]
|
#![doc(test = "hello")]
|
||||||
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
|
||||||
//~^^ WARN this was previously accepted by the compiler
|
|
||||||
#![doc(test(a))]
|
#![doc(test(a))]
|
||||||
//~^ ERROR unknown `doc(test)` attribute `a`
|
//~^ ERROR unknown `doc(test)` attribute `a`
|
||||||
//~^^ WARN this was previously accepted by the compiler
|
|
||||||
|
|
||||||
pub fn foo() {}
|
pub fn foo() {}
|
||||||
|
|
|
@ -4,8 +4,6 @@ error: `#[doc(test(...)]` takes a list of attributes
|
||||||
LL | #![doc(test)]
|
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
|
note: the lint level is defined here
|
||||||
--> $DIR/doc-test-attr.rs:2:9
|
--> $DIR/doc-test-attr.rs:2:9
|
||||||
|
|
|
|
||||||
|
@ -13,22 +11,16 @@ LL | #![deny(invalid_doc_attributes)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: `#[doc(test(...)]` takes a list of 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")]
|
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`
|
error: unknown `doc(test)` attribute `a`
|
||||||
--> $DIR/doc-test-attr.rs:10:13
|
--> $DIR/doc-test-attr.rs:8:13
|
||||||
|
|
|
|
||||||
LL | #![doc(test(a))]
|
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
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: malformed `cfi_encoding` attribute input
|
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]
|
LL | #[cfi_encoding]
|
||||||
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "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…
Add table
Add a link
Reference in a new issue