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:
bors 2024-03-02 00:06:46 +00:00
commit eaee1e9453
137 changed files with 1165 additions and 708 deletions

View File

@ -1631,7 +1631,9 @@ fn no_gc_sections(&mut self) {
fn optimize(&mut self) {}
fn pgo_gen(&mut self) {}
fn pgo_gen(&mut self) {
self.cmd.arg("-bdbg:namedsects:ss");
}
fn control_flow_guard(&mut self) {}

View File

@ -428,7 +428,7 @@ fn from_span_etc(
}
fn from_span_full(
span: Span,
mut span: Span,
is_primary: bool,
label: Option<String>,
suggestion: Option<(&String, Applicability)>,
@ -436,6 +436,16 @@ fn from_span_full(
je: &JsonEmitter,
) -> DiagnosticSpan {
let start = je.sm.lookup_char_pos(span.lo());
// If this goes from the start of a line to the end and the replacement
// is an empty string, increase the length to include the newline so we don't
// leave an empty line
if start.col.0 == 0
&& suggestion.map_or(false, |(s, _)| s.is_empty())
&& let Ok(after) = je.sm.span_to_next_source(span)
&& after.starts_with('\n')
{
span = span.with_hi(span.hi() + rustc_span::BytePos(1));
}
let end = je.sm.lookup_char_pos(span.hi());
let backtrace_step = backtrace.next().map(|bt| {
let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);

View File

@ -1744,7 +1744,11 @@ pub(in super::super) fn check_block_with_expected(
Ty::new_unit(self.tcx),
);
}
if !self.consider_removing_semicolon(blk, expected_ty, err) {
if !self.err_ctxt().consider_removing_semicolon(
blk,
expected_ty,
err,
) {
self.err_ctxt().consider_returning_binding(
blk,
expected_ty,

View File

@ -22,7 +22,7 @@
Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::traits::{self, StatementAsExpression};
use rustc_infer::traits::{self};
use rustc_middle::lint::in_external_macro;
use rustc_middle::middle::stability::EvalResult;
use rustc_middle::ty::print::with_no_trimmed_paths;
@ -1791,45 +1791,6 @@ fn note_type_is_not_clone_inner_expr<'b>(
}
}
/// A common error is to add an extra semicolon:
///
/// ```compile_fail,E0308
/// fn foo() -> usize {
/// 22;
/// }
/// ```
///
/// This routine checks if the final statement in a block is an
/// expression with an explicit semicolon whose type is compatible
/// with `expected_ty`. If so, it suggests removing the semicolon.
pub(crate) fn consider_removing_semicolon(
&self,
blk: &'tcx hir::Block<'tcx>,
expected_ty: Ty<'tcx>,
err: &mut Diag<'_>,
) -> bool {
if let Some((span_semi, boxed)) = self.err_ctxt().could_remove_semicolon(blk, expected_ty) {
if let StatementAsExpression::NeedsBoxing = boxed {
err.span_suggestion_verbose(
span_semi,
"consider removing this semicolon and boxing the expression",
"",
Applicability::HasPlaceholders,
);
} else {
err.span_suggestion_short(
span_semi,
"remove this semicolon to return this value",
"",
Applicability::MachineApplicable,
);
}
true
} else {
false
}
}
pub(crate) fn is_field_suggestable(
&self,
field: &ty::FieldDef,

View File

@ -1989,6 +1989,7 @@ enum Similar<'tcx> {
self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
self.suggest_function_pointers(cause, span, &exp_found, diag);
self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
}
}

View File

@ -1,8 +1,13 @@
use crate::infer::error_reporting::hir::Path;
use hir::def::CtorKind;
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
use hir::{Local, QPath};
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diag};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::MatchSource;
use rustc_hir::Node;
use rustc_middle::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
StatementAsExpression,
@ -293,6 +298,97 @@ pub(super) fn suggest_accessing_field_where_appropriate(
}
}
pub(super) fn suggest_turning_stmt_into_expr(
&self,
cause: &ObligationCause<'tcx>,
exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
diag: &mut Diag<'_>,
) {
let ty::error::ExpectedFound { expected, found } = exp_found;
if !found.peel_refs().is_unit() {
return;
}
let ObligationCauseCode::BlockTailExpression(hir_id, MatchSource::Normal) = cause.code()
else {
return;
};
let node = self.tcx.hir_node(*hir_id);
let mut blocks = vec![];
if let hir::Node::Block(block) = node
&& let Some(expr) = block.expr
&& let hir::ExprKind::Path(QPath::Resolved(_, Path { res, .. })) = expr.kind
&& let Res::Local(local) = res
&& let Node::Local(Local { init: Some(init), .. }) = self.tcx.parent_hir_node(*local)
{
fn collect_blocks<'hir>(expr: &hir::Expr<'hir>, blocks: &mut Vec<&hir::Block<'hir>>) {
match expr.kind {
// `blk1` and `blk2` must be have the same types, it will be reported before reaching here
hir::ExprKind::If(_, blk1, Some(blk2)) => {
collect_blocks(blk1, blocks);
collect_blocks(blk2, blocks);
}
hir::ExprKind::Match(_, arms, _) => {
// all arms must have same types
for arm in arms.iter() {
collect_blocks(arm.body, blocks);
}
}
hir::ExprKind::Block(blk, _) => {
blocks.push(blk);
}
_ => {}
}
}
collect_blocks(init, &mut blocks);
}
let expected_inner: Ty<'_> = expected.peel_refs();
for block in blocks.iter() {
self.consider_removing_semicolon(block, expected_inner, diag);
}
}
/// A common error is to add an extra semicolon:
///
/// ```compile_fail,E0308
/// fn foo() -> usize {
/// 22;
/// }
/// ```
///
/// This routine checks if the final statement in a block is an
/// expression with an explicit semicolon whose type is compatible
/// with `expected_ty`. If so, it suggests removing the semicolon.
pub fn consider_removing_semicolon(
&self,
blk: &'tcx hir::Block<'tcx>,
expected_ty: Ty<'tcx>,
diag: &mut Diag<'_>,
) -> bool {
if let Some((span_semi, boxed)) = self.could_remove_semicolon(blk, expected_ty) {
if let StatementAsExpression::NeedsBoxing = boxed {
diag.span_suggestion_verbose(
span_semi,
"consider removing this semicolon and boxing the expression",
"",
Applicability::HasPlaceholders,
);
} else {
diag.span_suggestion_short(
span_semi,
"remove this semicolon to return this value",
"",
Applicability::MachineApplicable,
);
}
true
} else {
false
}
}
pub(super) fn suggest_function_pointers(
&self,
cause: &ObligationCause<'tcx>,

View File

@ -135,16 +135,18 @@ pub struct FulfillmentError<'tcx> {
#[derive(Clone)]
pub enum FulfillmentErrorCode<'tcx> {
/// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
/// Inherently impossible to fulfill; this trait is implemented if and only
/// if it is already implemented.
Cycle(Vec<PredicateObligation<'tcx>>),
SelectionError(SelectionError<'tcx>),
ProjectionError(MismatchedProjectionTypes<'tcx>),
SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
Ambiguity {
/// Overflow reported from the new solver `-Znext-solver`, which will
/// be reported as an regular error as opposed to a fatal error.
overflow: bool,
/// Overflow is only `Some(suggest_recursion_limit)` when using the next generation
/// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by
/// emitting a fatal error instead.
overflow: Option<bool>,
},
}

View File

@ -47,8 +47,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ConstEquateError(ref a, ref b) => {
write!(f, "CodeConstEquateError({a:?}, {b:?})")
}
Ambiguity { overflow: false } => write!(f, "Ambiguity"),
Ambiguity { overflow: true } => write!(f, "Overflow"),
Ambiguity { overflow: None } => write!(f, "Ambiguity"),
Ambiguity { overflow: Some(suggest_increasing_limit) } => {
write!(f, "Overflow({suggest_increasing_limit})")
}
Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"),
}
}

View File

@ -3586,18 +3586,9 @@
/// being validated. Usually these should be rejected as a hard error,
/// but this lint was introduced to avoid breaking any existing
/// crates which included them.
///
/// This is a [future-incompatible] lint to transition this to a hard
/// error in the future. See [issue #82730] for more details.
///
/// [issue #82730]: https://github.com/rust-lang/rust/issues/82730
pub INVALID_DOC_ATTRIBUTES,
Warn,
Deny,
"detects invalid `#[doc(...)]` attributes",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
reference: "issue #82730 <https://github.com/rust-lang/rust/issues/82730>",
};
}
declare_lint! {

View File

@ -60,7 +60,6 @@ pub enum Certainty {
impl Certainty {
pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
pub const OVERFLOW: Certainty = Certainty::Maybe(MaybeCause::Overflow);
/// Use this function to merge the certainty of multiple nested subgoals.
///
@ -79,16 +78,13 @@ pub fn unify_with(self, other: Certainty) -> Certainty {
(Certainty::Yes, Certainty::Yes) => Certainty::Yes,
(Certainty::Yes, Certainty::Maybe(_)) => other,
(Certainty::Maybe(_), Certainty::Yes) => self,
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Ambiguity)) => {
Certainty::Maybe(MaybeCause::Ambiguity)
}
(Certainty::Maybe(MaybeCause::Ambiguity), Certainty::Maybe(MaybeCause::Overflow))
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Ambiguity))
| (Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow)) => {
Certainty::Maybe(MaybeCause::Overflow)
}
(Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
}
}
pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
}
}
/// Why we failed to evaluate a goal.
@ -99,7 +95,21 @@ pub enum MaybeCause {
/// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
Ambiguity,
/// We gave up due to an overflow, most often by hitting the recursion limit.
Overflow,
Overflow { suggest_increasing_limit: bool },
}
impl MaybeCause {
fn unify_with(self, other: MaybeCause) -> MaybeCause {
match (self, other) {
(MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
(MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
(MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
(
MaybeCause::Overflow { suggest_increasing_limit: a },
MaybeCause::Overflow { suggest_increasing_limit: b },
) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]

View File

@ -1097,21 +1097,18 @@ enum TestKind<'tcx> {
variants: BitSet<VariantIdx>,
},
/// Test what value an integer, `bool`, or `char` has.
/// Test what value an integer or `char` has.
SwitchInt {
/// The type of the value that we're testing.
switch_ty: Ty<'tcx>,
/// The (ordered) set of values that we test for.
///
/// For integers and `char`s we create a branch to each of the values in
/// `options`, as well as an "otherwise" branch for all other values, even
/// in the (rare) case that `options` is exhaustive.
///
/// For `bool` we always generate two edges, one for `true` and one for
/// `false`.
/// We create a branch to each of the values in `options`, as well as an "otherwise" branch
/// for all other values, even in the (rare) case that `options` is exhaustive.
options: FxIndexMap<Const<'tcx>, u128>,
},
/// Test what value a `bool` has.
If,
/// Test for equality with value, possibly after an unsizing coercion to
/// `ty`,
Eq {
@ -1617,7 +1614,7 @@ fn pick_test(
// a test like SwitchInt, we may want to add cases based on the candidates that are
// available
match test.kind {
TestKind::SwitchInt { switch_ty: _, ref mut options } => {
TestKind::SwitchInt { ref mut options } => {
for candidate in candidates.iter() {
if !self.add_cases_to_switch(&match_place, candidate, options) {
break;

View File

@ -34,12 +34,12 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
TestKind::Switch { adt_def, variants: BitSet::new_empty(adt_def.variants().len()) }
}
TestCase::Constant { .. } if match_pair.pattern.ty.is_bool() => TestKind::If,
TestCase::Constant { .. } if is_switch_ty(match_pair.pattern.ty) => {
// For integers, we use a `SwitchInt` match, which allows
// us to handle more cases.
TestKind::SwitchInt {
switch_ty: match_pair.pattern.ty,
// these maps are empty to start; cases are
// added below in add_cases_to_switch
options: Default::default(),
@ -182,34 +182,29 @@ pub(super) fn perform_test(
);
}
TestKind::SwitchInt { switch_ty, ref options } => {
let terminator = if *switch_ty.kind() == ty::Bool {
assert!(!options.is_empty() && options.len() <= 2);
let [first_bb, second_bb] = *target_blocks else {
bug!("`TestKind::SwitchInt` on `bool` should have two targets")
};
let (true_bb, false_bb) = match options[0] {
1 => (first_bb, second_bb),
0 => (second_bb, first_bb),
v => span_bug!(test.span, "expected boolean value but got {:?}", v),
};
TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb)
} else {
// The switch may be inexhaustive so we have a catch all block
debug_assert_eq!(options.len() + 1, target_blocks.len());
let otherwise_block = *target_blocks.last().unwrap();
let switch_targets = SwitchTargets::new(
options.values().copied().zip(target_blocks),
otherwise_block,
);
TerminatorKind::SwitchInt {
discr: Operand::Copy(place),
targets: switch_targets,
}
TestKind::SwitchInt { ref options } => {
// The switch may be inexhaustive so we have a catch-all block
debug_assert_eq!(options.len() + 1, target_blocks.len());
let otherwise_block = *target_blocks.last().unwrap();
let switch_targets = SwitchTargets::new(
options.values().copied().zip(target_blocks),
otherwise_block,
);
let terminator = TerminatorKind::SwitchInt {
discr: Operand::Copy(place),
targets: switch_targets,
};
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
}
TestKind::If => {
let [false_bb, true_bb] = *target_blocks else {
bug!("`TestKind::If` should have two targets")
};
let terminator = TerminatorKind::if_(Operand::Copy(place), true_bb, false_bb);
self.cfg.terminate(block, self.source_info(match_start_span), terminator);
}
TestKind::Eq { value, ty } => {
let tcx = self.tcx;
let [success_block, fail_block] = *target_blocks else {
@ -583,24 +578,20 @@ pub(super) fn sort_candidate<'pat>(
fully_matched = true;
Some(variant_index.as_usize())
}
(&TestKind::Switch { .. }, _) => {
fully_matched = false;
None
}
// If we are performing a switch over integers, then this informs integer
// equality, but nothing else.
//
// FIXME(#29623) we could use PatKind::Range to rule
// things out here, in some cases.
(TestKind::SwitchInt { switch_ty: _, options }, TestCase::Constant { value })
(TestKind::SwitchInt { options }, TestCase::Constant { value })
if is_switch_ty(match_pair.pattern.ty) =>
{
fully_matched = true;
let index = options.get_index_of(value).unwrap();
Some(index)
}
(TestKind::SwitchInt { switch_ty: _, options }, TestCase::Range(range)) => {
(TestKind::SwitchInt { options }, TestCase::Range(range)) => {
fully_matched = false;
let not_contained =
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
@ -611,7 +602,15 @@ pub(super) fn sort_candidate<'pat>(
options.len()
})
}
(&TestKind::SwitchInt { .. }, _) => {
(&TestKind::If, TestCase::Constant { value }) => {
fully_matched = true;
let value = value.try_eval_bool(self.tcx, self.param_env).unwrap_or_else(|| {
span_bug!(test.span, "expected boolean value but got {value:?}")
});
Some(value as usize)
}
(&TestKind::If, _) => {
fully_matched = false;
None
}
@ -703,34 +702,25 @@ pub(super) fn sort_candidate<'pat>(
None
}
}
(&TestKind::Range { .. }, _) => {
fully_matched = false;
None
// FIXME(#29623): return `Some(1)` when the values are different.
(TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val })
if test_val == case_val =>
{
fully_matched = true;
Some(0)
}
(&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => {
// The call to `self.test(&match_pair)` below is not actually used to generate any
// MIR. Instead, we just want to compare with `test` (the parameter of the method)
// to see if it is the same.
//
// However, at this point we can still encounter or-patterns that were extracted
// from previous calls to `sort_candidate`, so we need to manually address that
// case to avoid panicking in `self.test()`.
if let TestCase::Or { .. } = &match_pair.test_case {
return None;
}
// These are all binary tests.
//
// FIXME(#29623) we can be more clever here
let pattern_test = self.test(match_pair);
if pattern_test.kind == test.kind {
fully_matched = true;
Some(0)
} else {
fully_matched = false;
None
}
(
TestKind::Switch { .. }
| TestKind::SwitchInt { .. }
| TestKind::Len { .. }
| TestKind::Range { .. }
| TestKind::Eq { .. },
_,
) => {
fully_matched = false;
None
}
};
@ -763,7 +753,7 @@ fn values_not_contained_in_range(
impl Test<'_> {
pub(super) fn targets(&self) -> usize {
match self.kind {
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } => 2,
TestKind::Eq { .. } | TestKind::Range(_) | TestKind::Len { .. } | TestKind::If => 2,
TestKind::Switch { adt_def, .. } => {
// While the switch that we generate doesn't test for all
// variants, we have a target for each variant and the
@ -771,21 +761,13 @@ pub(super) fn targets(&self) -> usize {
// specified have the same block.
adt_def.variants().len() + 1
}
TestKind::SwitchInt { switch_ty, ref options, .. } => {
if switch_ty.is_bool() {
// `bool` is special cased in `perform_test` to always
// branch to two blocks.
2
} else {
options.len() + 1
}
}
TestKind::SwitchInt { ref options } => options.len() + 1,
}
}
}
fn is_switch_ty(ty: Ty<'_>) -> bool {
ty.is_integral() || ty.is_char() || ty.is_bool()
ty.is_integral() || ty.is_char()
}
fn trait_method<'tcx>(

View File

@ -6,11 +6,13 @@
use rustc_middle::ty;
use rustc_target::abi::call::Conv;
use stable_mir::abi::{
ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding,
TyAndLayout, ValueAbi, VariantsShape,
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
WrappingRange,
};
use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx};
use stable_mir::{opaque, Opaque};
use stable_mir::opaque;
use stable_mir::target::MachineSize as Size;
use stable_mir::ty::{Align, IndexedVal, VariantIdx};
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
type T = VariantIdx;
@ -220,7 +222,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Size {
type T = Size;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
self.bytes_usize()
Size::from_bits(self.bits_usize())
}
}
@ -233,9 +235,62 @@ fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
}
impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
type T = Opaque;
type T = Scalar;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
opaque(self)
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
match self {
rustc_abi::Scalar::Initialized { value, valid_range } => Scalar::Initialized {
value: value.stable(tables),
valid_range: valid_range.stable(tables),
},
rustc_abi::Scalar::Union { value } => Scalar::Union { value: value.stable(tables) },
}
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::Primitive {
type T = Primitive;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
match self {
rustc_abi::Primitive::Int(length, signed) => {
Primitive::Int { length: length.stable(tables), signed: *signed }
}
rustc_abi::Primitive::F16 => Primitive::Float { length: FloatLength::F16 },
rustc_abi::Primitive::F32 => Primitive::Float { length: FloatLength::F32 },
rustc_abi::Primitive::F64 => Primitive::Float { length: FloatLength::F64 },
rustc_abi::Primitive::F128 => Primitive::Float { length: FloatLength::F128 },
rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)),
}
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::AddressSpace {
type T = AddressSpace;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
AddressSpace(self.0)
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::Integer {
type T = IntegerLength;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
match self {
rustc_abi::Integer::I8 => IntegerLength::I8,
rustc_abi::Integer::I16 => IntegerLength::I16,
rustc_abi::Integer::I32 => IntegerLength::I32,
rustc_abi::Integer::I64 => IntegerLength::I64,
rustc_abi::Integer::I128 => IntegerLength::I128,
}
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
type T = WrappingRange;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
WrappingRange { start: self.start, end: self.end }
}
}

View File

@ -36,11 +36,13 @@ pub(super) fn compute_alias_relate_goal(
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
return self
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
};
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW);
return self
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
};
let variance = match direction {

View File

@ -7,6 +7,7 @@
BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::MaybeCause;
use rustc_infer::traits::ObligationCause;
use rustc_middle::infer::canonical::CanonicalVarInfos;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
@ -29,7 +30,7 @@
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
use super::inspect::ProofTreeBuilder;
use super::{search_graph, GoalEvaluationKind};
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
use super::{search_graph::SearchGraph, Goal};
use super::{GoalSource, SolverMode};
pub use select::InferCtxtSelectExt;
@ -154,10 +155,6 @@ pub(super) fn solver_mode(&self) -> SolverMode {
self.search_graph.solver_mode()
}
pub(super) fn local_overflow_limit(&self) -> usize {
self.search_graph.local_overflow_limit()
}
/// Creates a root evaluation context and search graph. This should only be
/// used from outside of any evaluation, and other methods should be preferred
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
@ -167,7 +164,7 @@ fn enter_root<R>(
f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
let mut search_graph = search_graph::SearchGraph::new(infcx.tcx, mode);
let mut search_graph = search_graph::SearchGraph::new(mode);
let mut ecx = EvalCtxt {
search_graph: &mut search_graph,
@ -388,16 +385,18 @@ fn instantiate_response_discarding_overflow(
&& source != GoalSource::ImplWhereBound
};
if response.value.certainty == Certainty::OVERFLOW && !keep_overflow_constraints() {
(Certainty::OVERFLOW, false)
} else {
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|| !response.value.external_constraints.opaque_types.is_empty();
let certainty =
self.instantiate_and_apply_query_response(param_env, original_values, response);
(certainty, has_changed)
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty
&& !keep_overflow_constraints()
{
return (response.value.certainty, false);
}
let has_changed = !response.value.var_values.is_identity_modulo_regions()
|| !response.value.external_constraints.opaque_types.is_empty();
let certainty =
self.instantiate_and_apply_query_response(param_env, original_values, response);
(certainty, has_changed)
}
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
@ -466,8 +465,8 @@ pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolutio
let inspect = self.inspect.new_evaluate_added_goals();
let inspect = core::mem::replace(&mut self.inspect, inspect);
let mut response = Ok(Certainty::OVERFLOW);
for _ in 0..self.local_overflow_limit() {
let mut response = Ok(Certainty::overflow(false));
for _ in 0..FIXPOINT_STEP_LIMIT {
// FIXME: This match is a bit ugly, it might be nice to change the inspect
// stuff to use a closure instead. which should hopefully simplify this a bit.
match self.evaluate_added_goals_step() {

View File

@ -24,7 +24,7 @@
/// It is also likely that we want to use slightly different datastructures
/// here as this will have to deal with far more root goals than `evaluate_all`.
pub struct FulfillmentCtxt<'tcx> {
obligations: Vec<PredicateObligation<'tcx>>,
obligations: ObligationStorage<'tcx>,
/// The snapshot in which this context was created. Using the context
/// outside of this snapshot leads to subtle bugs if the snapshot
@ -33,6 +33,57 @@ pub struct FulfillmentCtxt<'tcx> {
usable_in_snapshot: usize,
}
#[derive(Default)]
struct ObligationStorage<'tcx> {
/// Obligations which resulted in an overflow in fulfillment itself.
///
/// We cannot eagerly return these as error so we instead store them here
/// to avoid recomputing them each time `select_where_possible` is called.
/// This also allows us to return the correct `FulfillmentError` for them.
overflowed: Vec<PredicateObligation<'tcx>>,
pending: Vec<PredicateObligation<'tcx>>,
}
impl<'tcx> ObligationStorage<'tcx> {
fn register(&mut self, obligation: PredicateObligation<'tcx>) {
self.pending.push(obligation);
}
fn clone_pending(&self) -> Vec<PredicateObligation<'tcx>> {
let mut obligations = self.pending.clone();
obligations.extend(self.overflowed.iter().cloned());
obligations
}
fn take_pending(&mut self) -> Vec<PredicateObligation<'tcx>> {
let mut obligations = mem::take(&mut self.pending);
obligations.extend(self.overflowed.drain(..));
obligations
}
fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> {
mem::take(&mut self.pending).into_iter()
}
fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
infcx.probe(|_| {
// IMPORTANT: we must not use solve any inference variables in the obligations
// as this is all happening inside of a probe. We use a probe to make sure
// we get all obligations involved in the overflow. We pretty much check: if
// we were to do another step of `select_where_possible`, which goals would
// change.
self.overflowed.extend(self.pending.extract_if(|o| {
let goal = o.clone().into();
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::Never).0;
match result {
Ok((has_changed, _)) => has_changed,
_ => false,
}
}));
})
}
}
impl<'tcx> FulfillmentCtxt<'tcx> {
pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
assert!(
@ -40,7 +91,10 @@ pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> {
"new trait solver fulfillment context created when \
infcx is set up for old trait solver"
);
FulfillmentCtxt { obligations: Vec::new(), usable_in_snapshot: infcx.num_open_snapshots() }
FulfillmentCtxt {
obligations: Default::default(),
usable_in_snapshot: infcx.num_open_snapshots(),
}
}
fn inspect_evaluated_obligation(
@ -67,40 +121,24 @@ fn register_predicate_obligation(
obligation: PredicateObligation<'tcx>,
) {
assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
self.obligations.push(obligation);
self.obligations.register(obligation);
}
fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
self.obligations
let mut errors: Vec<_> = self
.obligations
.pending
.drain(..)
.map(|obligation| {
let code = infcx.probe(|_| {
match infcx
.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::IfEnabled)
.0
{
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
FulfillmentErrorCode::Ambiguity { overflow: false }
}
Ok((_, Certainty::Maybe(MaybeCause::Overflow))) => {
FulfillmentErrorCode::Ambiguity { overflow: true }
}
Ok((_, Certainty::Yes)) => {
bug!("did not expect successful goal when collecting ambiguity errors")
}
Err(_) => {
bug!("did not expect selection error when collecting ambiguity errors")
}
}
});
.map(|obligation| fulfillment_error_for_stalled(infcx, obligation))
.collect();
FulfillmentError {
obligation: obligation.clone(),
code,
root_obligation: obligation,
}
})
.collect()
errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError {
root_obligation: obligation.clone(),
code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
obligation,
}));
errors
}
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
@ -108,79 +146,27 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
let mut errors = Vec::new();
for i in 0.. {
if !infcx.tcx.recursion_limit().value_within_limit(i) {
// Only return true errors that we have accumulated while processing;
// keep ambiguities around, *including overflows*, because they shouldn't
// be considered true errors.
self.obligations.on_fulfillment_overflow(infcx);
// Only return true errors that we have accumulated while processing.
return errors;
}
let mut has_changed = false;
for obligation in mem::take(&mut self.obligations) {
for obligation in self.obligations.unstalled_for_select() {
let goal = obligation.clone().into();
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::IfEnabled).0;
self.inspect_evaluated_obligation(infcx, &obligation, &result);
let (changed, certainty) = match result {
Ok(result) => result,
Err(NoSolution) => {
errors.push(FulfillmentError {
obligation: obligation.clone(),
code: match goal.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
FulfillmentErrorCode::ProjectionError(
// FIXME: This could be a `Sorts` if the term is a type
MismatchedProjectionTypes { err: TypeError::Mismatch },
)
}
ty::PredicateKind::NormalizesTo(..) => {
FulfillmentErrorCode::ProjectionError(
MismatchedProjectionTypes { err: TypeError::Mismatch },
)
}
ty::PredicateKind::AliasRelate(_, _, _) => {
FulfillmentErrorCode::ProjectionError(
MismatchedProjectionTypes { err: TypeError::Mismatch },
)
}
ty::PredicateKind::Subtype(pred) => {
let (a, b) = infcx.enter_forall_and_leak_universe(
goal.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(true, a, b);
FulfillmentErrorCode::SubtypeError(
expected_found,
TypeError::Sorts(expected_found),
)
}
ty::PredicateKind::Coerce(pred) => {
let (a, b) = infcx.enter_forall_and_leak_universe(
goal.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(false, a, b);
FulfillmentErrorCode::SubtypeError(
expected_found,
TypeError::Sorts(expected_found),
)
}
ty::PredicateKind::Clause(_)
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::Ambiguous => {
FulfillmentErrorCode::SelectionError(
SelectionError::Unimplemented,
)
}
ty::PredicateKind::ConstEquate(..) => {
bug!("unexpected goal: {goal:?}")
}
},
root_obligation: obligation,
});
errors.push(fulfillment_error_for_no_solution(infcx, obligation));
continue;
}
};
has_changed |= changed;
match certainty {
Certainty::Yes => {}
Certainty::Maybe(_) => self.obligations.push(obligation),
Certainty::Maybe(_) => self.obligations.register(obligation),
}
}
@ -193,13 +179,84 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.obligations.clone()
self.obligations.clone_pending()
}
fn drain_unstalled_obligations(
&mut self,
_: &InferCtxt<'tcx>,
) -> Vec<PredicateObligation<'tcx>> {
std::mem::take(&mut self.obligations)
self.obligations.take_pending()
}
}
fn fulfillment_error_for_no_solution<'tcx>(
infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) -> FulfillmentError<'tcx> {
let code = match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
FulfillmentErrorCode::ProjectionError(
// FIXME: This could be a `Sorts` if the term is a type
MismatchedProjectionTypes { err: TypeError::Mismatch },
)
}
ty::PredicateKind::NormalizesTo(..) => {
FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
err: TypeError::Mismatch,
})
}
ty::PredicateKind::AliasRelate(_, _, _) => {
FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
err: TypeError::Mismatch,
})
}
ty::PredicateKind::Subtype(pred) => {
let (a, b) = infcx.enter_forall_and_leak_universe(
obligation.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(true, a, b);
FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
}
ty::PredicateKind::Coerce(pred) => {
let (a, b) = infcx.enter_forall_and_leak_universe(
obligation.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(false, a, b);
FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
}
ty::PredicateKind::Clause(_)
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::Ambiguous => {
FulfillmentErrorCode::SelectionError(SelectionError::Unimplemented)
}
ty::PredicateKind::ConstEquate(..) => {
bug!("unexpected goal: {obligation:?}")
}
};
FulfillmentError { root_obligation: obligation.clone(), code, obligation }
}
fn fulfillment_error_for_stalled<'tcx>(
infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) -> FulfillmentError<'tcx> {
let code = infcx.probe(|_| {
match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 {
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
FulfillmentErrorCode::Ambiguity { overflow: None }
}
Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => {
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }
}
Ok((_, Certainty::Yes)) => {
bug!("did not expect successful goal when collecting ambiguity errors")
}
Err(_) => {
bug!("did not expect selection error when collecting ambiguity errors")
}
}
});
FulfillmentError { obligation: obligation.clone(), code, root_obligation: obligation }
}

View File

@ -42,6 +42,17 @@
pub(crate) use normalize::deeply_normalize_for_diagnostics;
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
/// How many fixpoint iterations we should attempt inside of the solver before bailing
/// with overflow.
///
/// We previously used `tcx.recursion_limit().0.checked_ilog2().unwrap_or(0)` for this.
/// However, it feels unlikely that uncreasing the recursion limit by a power of two
/// to get one more itereation is every useful or desirable. We now instead used a constant
/// here. If there ever ends up some use-cases where a bigger number of fixpoint iterations
/// is required, we can add a new attribute for that or revert this to be dependant on the
/// recursion limit again. However, this feels very unlikely.
const FIXPOINT_STEP_LIMIT: usize = 8;
#[derive(Debug, Clone, Copy)]
enum SolverMode {
/// Ordinary trait solving, using everywhere except for coherence.

View File

@ -1,3 +1,5 @@
use crate::solve::FIXPOINT_STEP_LIMIT;
use super::inspect;
use super::inspect::ProofTreeBuilder;
use super::SolverMode;
@ -99,7 +101,6 @@ fn is_empty(&self) -> bool {
pub(super) struct SearchGraph<'tcx> {
mode: SolverMode,
local_overflow_limit: usize,
/// The stack of goals currently being computed.
///
/// An element is *deeper* in the stack if its index is *lower*.
@ -116,10 +117,9 @@ pub(super) struct SearchGraph<'tcx> {
}
impl<'tcx> SearchGraph<'tcx> {
pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
pub(super) fn new(mode: SolverMode) -> SearchGraph<'tcx> {
Self {
mode,
local_overflow_limit: tcx.recursion_limit().0.checked_ilog2().unwrap_or(0) as usize,
stack: Default::default(),
provisional_cache: Default::default(),
cycle_participants: Default::default(),
@ -130,10 +130,6 @@ pub(super) fn solver_mode(&self) -> SolverMode {
self.mode
}
pub(super) fn local_overflow_limit(&self) -> usize {
self.local_overflow_limit
}
/// Update the stack and reached depths on cache hits.
#[instrument(level = "debug", skip(self))]
fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
@ -277,7 +273,7 @@ pub(super) fn with_new_goal(
}
inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow);
return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
return Self::response_no_constraints(tcx, input, Certainty::overflow(true));
};
// Try to fetch the goal from the global cache.
@ -370,7 +366,7 @@ pub(super) fn with_new_goal(
} else if is_coinductive_cycle {
Self::response_no_constraints(tcx, input, Certainty::Yes)
} else {
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW)
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
};
} else {
// No entry, we push this goal on the stack and try to prove it.
@ -398,7 +394,7 @@ pub(super) fn with_new_goal(
// of this we continuously recompute the cycle until the result
// of the previous iteration is equal to the final result, at which
// point we are done.
for _ in 0..self.local_overflow_limit() {
for _ in 0..FIXPOINT_STEP_LIMIT {
let result = prove_goal(self, inspect);
let stack_entry = self.pop_stack();
debug_assert_eq!(stack_entry.input, input);
@ -431,7 +427,8 @@ pub(super) fn with_new_goal(
} else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
Self::response_no_constraints(tcx, input, Certainty::Yes) == result
} else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
Self::response_no_constraints(tcx, input, Certainty::OVERFLOW) == result
Self::response_no_constraints(tcx, input, Certainty::overflow(false))
== result
} else {
false
};
@ -452,7 +449,7 @@ pub(super) fn with_new_goal(
debug!("canonical cycle overflow");
let current_entry = self.pop_stack();
debug_assert!(current_entry.has_been_used.is_empty());
let result = Self::response_no_constraints(tcx, input, Certainty::OVERFLOW);
let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false));
(current_entry, result)
});

View File

@ -22,7 +22,7 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::{util, TraitEngine, TraitEngineExt};
use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineExt};
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
use rustc_middle::traits::specialization_graph::OverlapMode;
@ -35,6 +35,8 @@
use std::fmt::Debug;
use std::ops::ControlFlow;
use super::error_reporting::suggest_new_overflow_limit;
/// Whether we do the orphan check relative to this crate or
/// to some remote crate.
#[derive(Copy, Clone, Debug)]
@ -56,6 +58,9 @@ pub struct OverlapResult<'tcx> {
/// `true` if the overlap might've been permitted before the shift
/// to universes.
pub involves_placeholder: bool,
/// Used in the new solver to suggest increasing the recursion limit.
pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
}
pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
@ -65,6 +70,18 @@ pub fn add_placeholder_note<G: EmissionGuarantee>(err: &mut Diag<'_, G>) {
);
}
pub fn suggest_increasing_recursion_limit<'tcx, G: EmissionGuarantee>(
tcx: TyCtxt<'tcx>,
err: &mut Diag<'_, G>,
overflowing_predicates: &[ty::Predicate<'tcx>],
) {
for pred in overflowing_predicates {
err.note(format!("overflow evaluating the requirement `{}`", pred));
}
suggest_new_overflow_limit(tcx, err);
}
#[derive(Debug, Clone, Copy)]
enum TrackAmbiguityCauses {
Yes,
@ -221,11 +238,13 @@ fn overlap<'tcx>(
),
);
let mut overflowing_predicates = Vec::new();
if overlap_mode.use_implicit_negative() {
if let Some(_failing_obligation) =
impl_intersection_has_impossible_obligation(selcx, &obligations)
{
return None;
match impl_intersection_has_impossible_obligation(selcx, &obligations) {
IntersectionHasImpossibleObligations::Yes => return None,
IntersectionHasImpossibleObligations::No { overflowing_predicates: p } => {
overflowing_predicates = p
}
}
}
@ -261,7 +280,12 @@ fn overlap<'tcx>(
impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header);
}
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
Some(OverlapResult {
impl_header,
intercrate_ambiguity_causes,
involves_placeholder,
overflowing_predicates,
})
}
#[instrument(level = "debug", skip(infcx), ret)]
@ -287,6 +311,19 @@ fn equate_impl_headers<'tcx>(
result.map(|infer_ok| infer_ok.obligations).ok()
}
/// The result of [fn impl_intersection_has_impossible_obligation].
enum IntersectionHasImpossibleObligations<'tcx> {
Yes,
No {
/// With `-Znext-solver=coherence`, some obligations may
/// fail if only the user increased the recursion limit.
///
/// We return those obligations here and mention them in the
/// error message.
overflowing_predicates: Vec<ty::Predicate<'tcx>>,
},
}
/// Check if both impls can be satisfied by a common type by considering whether
/// any of either impl's obligations is not known to hold.
///
@ -308,7 +345,7 @@ fn equate_impl_headers<'tcx>(
fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligations: &'a [PredicateObligation<'tcx>],
) -> Option<PredicateObligation<'tcx>> {
) -> IntersectionHasImpossibleObligations<'tcx> {
let infcx = selcx.infcx;
if infcx.next_trait_solver() {
@ -317,28 +354,42 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>(
// We only care about the obligations that are *definitely* true errors.
// Ambiguities do not prove the disjointness of two impls.
let mut errors = fulfill_cx.select_where_possible(infcx);
errors.pop().map(|err| err.obligation)
let errors = fulfill_cx.select_where_possible(infcx);
if errors.is_empty() {
let overflow_errors = fulfill_cx.collect_remaining_errors(infcx);
let overflowing_predicates = overflow_errors
.into_iter()
.filter(|e| match e.code {
FulfillmentErrorCode::Ambiguity { overflow: Some(true) } => true,
_ => false,
})
.map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate))
.collect();
IntersectionHasImpossibleObligations::No { overflowing_predicates }
} else {
IntersectionHasImpossibleObligations::Yes
}
} else {
obligations
.iter()
.find(|obligation| {
// We use `evaluate_root_obligation` to correctly track intercrate
// ambiguity clauses. We cannot use this in the new solver.
let evaluation_result = selcx.evaluate_root_obligation(obligation);
for obligation in obligations {
// We use `evaluate_root_obligation` to correctly track intercrate
// ambiguity clauses.
let evaluation_result = selcx.evaluate_root_obligation(obligation);
match evaluation_result {
Ok(result) => !result.may_apply(),
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
// since there can be instantiations of this goal that don't overflow and result in
// success. This isn't much of a problem in the old solver, since we treat overflow
// fatally (this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>),
// but in the new solver, this is very important for correctness, since overflow
// *must* be treated as ambiguity for completeness.
Err(_overflow) => false,
match evaluation_result {
Ok(result) => {
if !result.may_apply() {
return IntersectionHasImpossibleObligations::Yes;
}
}
})
.cloned()
// If overflow occurs, we need to conservatively treat the goal as possibly holding,
// since there can be instantiations of this goal that don't overflow and result in
// success. While this isn't much of a problem in the old solver, since we treat overflow
// fatally, this still can be encountered: <https://github.com/rust-lang/rust/issues/105231>.
Err(_overflow) => {}
}
}
IntersectionHasImpossibleObligations::No { overflowing_predicates: Vec::new() }
}
}

View File

@ -20,10 +20,9 @@
SelectionError, SignatureMismatch, TraitNotObjectSafe,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
MultiSpan, StashKey, StringPart,
};
use rustc_errors::codes::*;
use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
use rustc_errors::{Diag, EmissionGuarantee, ErrorGuaranteed, FatalError, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
@ -62,6 +61,22 @@ pub enum OverflowCause<'tcx> {
TraitSolver(ty::Predicate<'tcx>),
}
pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>(
tcx: TyCtxt<'tcx>,
err: &mut Diag<'_, G>,
) {
let suggested_limit = match tcx.recursion_limit() {
Limit(0) => Limit(2),
limit => limit * 2,
};
err.help(format!(
"consider increasing the recursion limit by adding a \
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
suggested_limit,
tcx.crate_name(LOCAL_CRATE),
));
}
#[extension(pub trait TypeErrCtxtExt<'tcx>)]
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn report_fulfillment_errors(
@ -263,7 +278,7 @@ fn with_short_path<'tcx, T>(tcx: TyCtxt<'tcx>, value: T) -> String
};
if suggest_increasing_limit {
self.suggest_new_overflow_limit(&mut err);
suggest_new_overflow_limit(self.tcx, &mut err);
}
err
@ -303,19 +318,6 @@ fn report_overflow_obligation<T>(
);
}
fn suggest_new_overflow_limit(&self, err: &mut Diag<'_>) {
let suggested_limit = match self.tcx.recursion_limit() {
Limit(0) => Limit(2),
limit => limit * 2,
};
err.help(format!(
"consider increasing the recursion limit by adding a \
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
suggested_limit,
self.tcx.crate_name(LOCAL_CRATE),
));
}
/// Reports that a cycle was detected which led to overflow and halts
/// compilation. This is equivalent to `report_overflow_obligation` except
/// that we can give a more helpful error message (and, in particular,
@ -335,12 +337,16 @@ fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>])
);
}
fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
fn report_overflow_no_abort(
&self,
obligation: PredicateObligation<'tcx>,
suggest_increasing_limit: bool,
) -> ErrorGuaranteed {
let obligation = self.resolve_vars_if_possible(obligation);
let mut err = self.build_overflow_error(
OverflowCause::TraitSolver(obligation.predicate),
obligation.cause.span,
true,
suggest_increasing_limit,
);
self.note_obligation_cause(&mut err, &obligation);
self.point_at_returns_when_relevant(&mut err, &obligation);
@ -1422,11 +1428,11 @@ fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuara
FulfillmentErrorCode::ProjectionError(ref e) => {
self.report_projection_error(&error.obligation, e)
}
FulfillmentErrorCode::Ambiguity { overflow: false } => {
FulfillmentErrorCode::Ambiguity { overflow: None } => {
self.maybe_report_ambiguity(&error.obligation)
}
FulfillmentErrorCode::Ambiguity { overflow: true } => {
self.report_overflow_no_abort(error.obligation.clone())
FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
}
FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
.report_mismatched_types(
@ -1910,6 +1916,9 @@ fn report_similar_impl_candidates(
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
},
);
if cand.references_error() {
return false;
}
err.highlighted_help(vec![
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
StringPart::highlighted("is"),
@ -1934,7 +1943,8 @@ fn report_similar_impl_candidates(
}
let other = if other { "other " } else { "" };
let report = |candidates: Vec<TraitRef<'tcx>>, err: &mut Diag<'_>| {
let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diag<'_>| {
candidates.retain(|tr| !tr.references_error());
if candidates.is_empty() {
return false;
}

View File

@ -138,7 +138,7 @@ fn collect_remaining_errors(
_infcx: &InferCtxt<'tcx>,
) -> Vec<FulfillmentError<'tcx>> {
self.predicates
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: false })
.to_errors(FulfillmentErrorCode::Ambiguity { overflow: None })
.into_iter()
.map(to_fulfillment_error)
.collect()

View File

@ -39,6 +39,7 @@ pub struct OverlapError<'tcx> {
pub self_ty: Option<Ty<'tcx>>,
pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause<'tcx>>,
pub involves_placeholder: bool,
pub overflowing_predicates: Vec<ty::Predicate<'tcx>>,
}
/// Given the generic parameters for the requested impl, translate it to the generic parameters
@ -435,6 +436,14 @@ fn decorate<'tcx, G: EmissionGuarantee>(
if overlap.involves_placeholder {
coherence::add_placeholder_note(err);
}
if !overlap.overflowing_predicates.is_empty() {
coherence::suggest_increasing_recursion_limit(
tcx,
err,
&overlap.overflowing_predicates,
);
}
}
let msg = DelayDm(|| {

View File

@ -103,6 +103,7 @@ fn insert(
self_ty: self_ty.has_concrete_skeleton().then_some(self_ty),
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
involves_placeholder: overlap.involves_placeholder,
overflowing_predicates: overlap.overflowing_predicates,
}
};

View File

@ -1,7 +1,11 @@
use crate::compiler_interface::with;
use crate::error;
use crate::mir::FieldIdx;
use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx};
use crate::target::{MachineInfo, MachineSize as Size};
use crate::ty::{Align, IndexedVal, Ty, VariantIdx};
use crate::Error;
use crate::Opaque;
use std::fmt::{self, Debug};
use std::num::NonZeroUsize;
use std::ops::RangeInclusive;
@ -100,7 +104,7 @@ pub fn is_sized(&self) -> bool {
/// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
pub fn is_1zst(&self) -> bool {
self.is_sized() && self.size == 0 && self.abi_align == 1
self.is_sized() && self.size.bits() == 0 && self.abi_align == 1
}
}
@ -245,8 +249,175 @@ pub fn is_unsized(&self) -> bool {
}
}
/// We currently do not support `Scalar`, and use opaque instead.
type Scalar = Opaque;
/// Information about one scalar component of a Rust type.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum Scalar {
Initialized {
/// The primitive type used to represent this value.
value: Primitive,
/// The range that represents valid values.
/// The range must be valid for the `primitive` size.
valid_range: WrappingRange,
},
Union {
/// Unions never have niches, so there is no `valid_range`.
/// Even for unions, we need to use the correct registers for the kind of
/// values inside the union, so we keep the `Primitive` type around.
/// It is also used to compute the size of the scalar.
value: Primitive,
},
}
impl Scalar {
pub fn has_niche(&self, target: &MachineInfo) -> bool {
match self {
Scalar::Initialized { value, valid_range } => {
!valid_range.is_full(value.size(target)).unwrap()
}
Scalar::Union { .. } => false,
}
}
}
/// Fundamental unit of memory access and layout.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Primitive {
/// The `bool` is the signedness of the `Integer` type.
///
/// One would think we would not care about such details this low down,
/// but some ABIs are described in terms of C types and ISAs where the
/// integer arithmetic is done on {sign,zero}-extended registers, e.g.
/// a negative integer passed by zero-extension will appear positive in
/// the callee, and most operations on it will produce the wrong values.
Int {
length: IntegerLength,
signed: bool,
},
Float {
length: FloatLength,
},
Pointer(AddressSpace),
}
impl Primitive {
pub fn size(self, target: &MachineInfo) -> Size {
match self {
Primitive::Int { length, .. } => Size::from_bits(length.bits()),
Primitive::Float { length } => Size::from_bits(length.bits()),
Primitive::Pointer(_) => target.pointer_width,
}
}
}
/// Enum representing the existing integer lengths.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum IntegerLength {
I8,
I16,
I32,
I64,
I128,
}
/// Enum representing the existing float lengths.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum FloatLength {
F16,
F32,
F64,
F128,
}
impl IntegerLength {
pub fn bits(self) -> usize {
match self {
IntegerLength::I8 => 8,
IntegerLength::I16 => 16,
IntegerLength::I32 => 32,
IntegerLength::I64 => 64,
IntegerLength::I128 => 128,
}
}
}
impl FloatLength {
pub fn bits(self) -> usize {
match self {
FloatLength::F16 => 16,
FloatLength::F32 => 32,
FloatLength::F64 => 64,
FloatLength::F128 => 128,
}
}
}
/// An identifier that specifies the address space that some operation
/// should operate on. Special address spaces have an effect on code generation,
/// depending on the target and the address spaces it implements.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AddressSpace(pub u32);
impl AddressSpace {
/// The default address space, corresponding to data space.
pub const DATA: Self = AddressSpace(0);
}
/// Inclusive wrap-around range of valid values (bitwise representation), that is, if
/// start > end, it represents `start..=MAX`, followed by `0..=end`.
///
/// That is, for an i8 primitive, a range of `254..=2` means following
/// sequence:
///
/// 254 (-2), 255 (-1), 0, 1, 2
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct WrappingRange {
pub start: u128,
pub end: u128,
}
impl WrappingRange {
/// Returns `true` if `size` completely fills the range.
#[inline]
pub fn is_full(&self, size: Size) -> Result<bool, Error> {
let Some(max_value) = size.unsigned_int_max() else {
return Err(error!("Expected size <= 128 bits, but found {} instead", size.bits()));
};
if self.start <= max_value && self.end <= max_value {
Ok(self.start == 0 && max_value == self.end)
} else {
Err(error!("Range `{self:?}` out of bounds for size `{}` bits.", size.bits()))
}
}
/// Returns `true` if `v` is contained in the range.
#[inline(always)]
pub fn contains(&self, v: u128) -> bool {
if self.wraps_around() {
self.start <= v || v <= self.end
} else {
self.start <= v && v <= self.end
}
}
/// Returns `true` if the range wraps around.
/// I.e., the range represents the union of `self.start..=MAX` and `0..=self.end`.
/// Returns `false` if this is a non-wrapping range, i.e.: `self.start..=self.end`.
#[inline]
pub fn wraps_around(&self) -> bool {
self.start > self.end
}
}
impl Debug for WrappingRange {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.start > self.end {
write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
} else {
write!(fmt, "{}..={}", self.start, self.end)?;
}
Ok(())
}
}
/// General language calling conventions.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]

View File

@ -5,12 +5,14 @@
//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled.
use std::fmt::{Debug, Display, Formatter};
use std::{error, fmt, io};
use std::{fmt, io};
macro_rules! error {
($fmt: literal $(,)?) => { Error(format!($fmt)) };
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
}
}
pub(crate) use error;
/// An error type used to represent an error that has already been reported by the compiler.
#[derive(Clone, Copy, PartialEq, Eq)]
@ -72,8 +74,9 @@ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
}
}
impl error::Error for Error {}
impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
impl std::error::Error for Error {}
impl<T> std::error::Error for CompilerError<T> where T: Display + Debug {}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {

View File

@ -30,21 +30,29 @@ pub enum Endian {
}
/// Represent the size of a component.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct MachineSize {
num_bits: usize,
}
impl MachineSize {
#[inline(always)]
pub fn bytes(self) -> usize {
self.num_bits / 8
}
#[inline(always)]
pub fn bits(self) -> usize {
self.num_bits
}
#[inline(always)]
pub fn from_bits(num_bits: usize) -> MachineSize {
MachineSize { num_bits }
}
#[inline]
pub fn unsigned_int_max(self) -> Option<u128> {
(self.num_bits <= 128).then(|| u128::MAX >> (128 - self.bits()))
}
}

View File

@ -324,7 +324,9 @@ pub fn is_str(&self) -> bool {
#[inline]
pub fn is_cstr(&self) -> bool {
let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else { return false };
let TyKind::RigidTy(RigidTy::Adt(def, _)) = self else {
return false;
};
with(|cx| cx.adt_is_cstr(*def))
}
@ -1032,10 +1034,13 @@ pub struct BoundTy {
}
pub type Bytes = Vec<Option<u8>>;
/// Size in bytes.
pub type Size = usize;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Prov(pub AllocId);
pub type Align = u64;
pub type Promoted = u32;
pub type InitMaskMaterialized = Vec<u64>;

View File

@ -2519,7 +2519,7 @@ pub fn contains(&self, x: &T) -> bool
cmp::SliceContains::slice_contains(x, self)
}
/// Returns `true` if `needle` is a prefix of the slice.
/// Returns `true` if `needle` is a prefix of the slice or equal to the slice.
///
/// # Examples
///
@ -2527,6 +2527,7 @@ pub fn contains(&self, x: &T) -> bool
/// let v = [10, 40, 30];
/// assert!(v.starts_with(&[10]));
/// assert!(v.starts_with(&[10, 40]));
/// assert!(v.starts_with(&v));
/// assert!(!v.starts_with(&[50]));
/// assert!(!v.starts_with(&[10, 50]));
/// ```
@ -2549,7 +2550,7 @@ pub fn starts_with(&self, needle: &[T]) -> bool
self.len() >= n && needle == &self[..n]
}
/// Returns `true` if `needle` is a suffix of the slice.
/// Returns `true` if `needle` is a suffix of the slice or equal to the slice.
///
/// # Examples
///
@ -2557,6 +2558,7 @@ pub fn starts_with(&self, needle: &[T]) -> bool
/// let v = [10, 40, 30];
/// assert!(v.ends_with(&[30]));
/// assert!(v.ends_with(&[40, 30]));
/// assert!(v.ends_with(&v));
/// assert!(!v.ends_with(&[50]));
/// assert!(!v.ends_with(&[50, 30]));
/// ```
@ -2582,7 +2584,8 @@ pub fn ends_with(&self, needle: &[T]) -> bool
/// Returns a subslice with the prefix removed.
///
/// If the slice starts with `prefix`, returns the subslice after the prefix, wrapped in `Some`.
/// If `prefix` is empty, simply returns the original slice.
/// If `prefix` is empty, simply returns the original slice. If `prefix` is equal to the
/// original slice, returns an empty slice.
///
/// If the slice does not start with `prefix`, returns `None`.
///
@ -2592,6 +2595,7 @@ pub fn ends_with(&self, needle: &[T]) -> bool
/// let v = &[10, 40, 30];
/// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
/// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
/// assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..]));
/// assert_eq!(v.strip_prefix(&[50]), None);
/// assert_eq!(v.strip_prefix(&[10, 50]), None);
///
@ -2620,7 +2624,8 @@ pub fn strip_prefix<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> Op
/// Returns a subslice with the suffix removed.
///
/// If the slice ends with `suffix`, returns the subslice before the suffix, wrapped in `Some`.
/// If `suffix` is empty, simply returns the original slice.
/// If `suffix` is empty, simply returns the original slice. If `suffix` is equal to the
/// original slice, returns an empty slice.
///
/// If the slice does not end with `suffix`, returns `None`.
///
@ -2630,6 +2635,7 @@ pub fn strip_prefix<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> Op
/// let v = &[10, 40, 30];
/// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
/// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..]));
/// assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..]));
/// assert_eq!(v.strip_suffix(&[50]), None);
/// assert_eq!(v.strip_suffix(&[50, 30]), None);
/// ```

View File

@ -26,6 +26,7 @@ fn main() {
"InstrProfilingMerge.c",
"InstrProfilingMergeFile.c",
"InstrProfilingNameVar.c",
"InstrProfilingPlatformAIX.c",
"InstrProfilingPlatformDarwin.c",
"InstrProfilingPlatformFuchsia.c",
"InstrProfilingPlatformLinux.c",

View File

@ -19,12 +19,10 @@ struct FooDefault<'a> {
}
#[derive(Default)]
struct TupleDefault(bool, i32, u64);
struct FooND1 {
a: bool,
}
@ -73,7 +71,6 @@ impl Default for FooNDVec {
struct StrDefault<'a>(&'a str);
#[derive(Default)]
struct AlreadyDerived(i32, bool);
@ -96,7 +93,6 @@ mac!(0);
#[derive(Default)]
struct Y(u32);
struct RustIssue26925<T> {
a: Option<T>,
}
@ -132,12 +128,10 @@ struct WithoutSelfCurly {
}
#[derive(Default)]
struct WithoutSelfParan(bool);
// https://github.com/rust-lang/rust-clippy/issues/7655
pub struct SpecializedImpl2<T> {
@ -184,7 +178,6 @@ pub struct RepeatDefault1 {
}
pub struct RepeatDefault2 {
a: [i8; 33],
}
@ -216,7 +209,6 @@ pub enum SimpleEnum {
}
pub enum NonExhaustiveEnum {
Foo,
#[non_exhaustive]

View File

@ -5,7 +5,6 @@
struct Foo;
// shouldn't cause an error
struct Bar;
@ -19,5 +18,4 @@ impl Drop for Bar {
struct Baz;
fn main() {}

View File

@ -6,13 +6,10 @@
extern crate proc_macros;
use proc_macros::external;
pub fn must_use_default() {}
pub fn must_use_unit() -> () {}
pub fn must_use_with_note() {}
fn main() {

View File

@ -4,7 +4,6 @@
use core;
use serde as edres;
pub use serde;

View File

@ -3797,9 +3797,9 @@
"ui/rust-2018/uniform-paths/issue-56596-2.rs",
"ui/rust-2018/uniform-paths/issue-56596.rs",
"ui/rust-2018/uniform-paths/issue-87932.rs",
"ui/sanitize/issue-111184-coroutine-witness.rs",
"ui/sanitize/issue-114275-cfi-const-expr-in-arry-len.rs",
"ui/sanitize/issue-72154-lifetime-markers.rs",
"ui/sanitizer/issue-111184-cfi-coroutine-witness.rs",
"ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs",
"ui/sanitizer/issue-72154-address-lifetime-markers.rs",
"ui/self/issue-61882-2.rs",
"ui/self/issue-61882.rs",
"ui/simd/intrinsic/issue-85855.rs",

View File

@ -42,15 +42,11 @@
}
bb2: {
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
}
bb3: {
- falseEdge -> [real: bb20, imaginary: bb4];
- }
-
- bb4: {
StorageLive(_15);
_15 = (_2.1: bool);
StorageLive(_16);
@ -59,8 +55,12 @@
+ goto -> bb16;
}
bb4: {
- falseEdge -> [real: bb20, imaginary: bb3];
- }
-
- bb5: {
- falseEdge -> [real: bb13, imaginary: bb3];
- falseEdge -> [real: bb13, imaginary: bb4];
- }
-
- bb6: {
@ -68,7 +68,6 @@
- }
-
- bb7: {
+ bb4: {
_0 = const 1_i32;
- drop(_7) -> [return: bb18, unwind: bb25];
+ drop(_7) -> [return: bb15, unwind: bb22];
@ -184,7 +183,7 @@
StorageDead(_12);
StorageDead(_8);
StorageDead(_6);
- falseEdge -> [real: bb2, imaginary: bb3];
- falseEdge -> [real: bb2, imaginary: bb4];
+ goto -> bb2;
}

View File

@ -42,15 +42,11 @@
}
bb2: {
- switchInt((_2.0: bool)) -> [0: bb4, otherwise: bb3];
- switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb4];
+ switchInt((_2.0: bool)) -> [0: bb3, otherwise: bb17];
}
bb3: {
- falseEdge -> [real: bb20, imaginary: bb4];
- }
-
- bb4: {
StorageLive(_15);
_15 = (_2.1: bool);
StorageLive(_16);
@ -59,8 +55,12 @@
+ goto -> bb16;
}
bb4: {
- falseEdge -> [real: bb20, imaginary: bb3];
- }
-
- bb5: {
- falseEdge -> [real: bb13, imaginary: bb3];
- falseEdge -> [real: bb13, imaginary: bb4];
- }
-
- bb6: {
@ -68,7 +68,6 @@
- }
-
- bb7: {
+ bb4: {
_0 = const 1_i32;
- drop(_7) -> [return: bb18, unwind: bb25];
+ drop(_7) -> [return: bb15, unwind: bb22];
@ -184,7 +183,7 @@
StorageDead(_12);
StorageDead(_8);
StorageDead(_6);
- falseEdge -> [real: bb2, imaginary: bb3];
- falseEdge -> [real: bb2, imaginary: bb4];
+ goto -> bb2;
}

View File

@ -1,10 +1,6 @@
//@ check-pass
#[doc(include = "external-cross-doc.md")]
//~^ WARNING unknown `doc` attribute `include`
//~^ ERROR unknown `doc` attribute `include`
//~| HELP use `doc = include_str!` instead
// FIXME(#85497): make this a deny instead so it's more clear what's happening
//~| NOTE on by default
//~| WARNING previously accepted
//~| NOTE see issue #82730
pub struct NeedMoreDocs;

View File

@ -1,12 +1,10 @@
warning: unknown `doc` attribute `include`
--> $DIR/doc-include-suggestion.rs:3:7
error: unknown `doc` attribute `include`
--> $DIR/doc-include-suggestion.rs:1:7
|
LL | #[doc(include = "external-cross-doc.md")]
| ------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- help: use `doc = include_str!` instead: `#[doc = include_str!("external-cross-doc.md")]`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `#[warn(invalid_doc_attributes)]` on by default
= note: `#[deny(invalid_doc_attributes)]` on by default
warning: 1 warning emitted
error: aborting due to 1 previous error

View File

@ -1,14 +1,10 @@
#![crate_type = "lib"]
#![deny(invalid_doc_attributes)]
#![doc(test)]
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
//~^^ WARN this was previously accepted by the compiler
#![doc(test = "hello")]
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
//~^^ WARN this was previously accepted by the compiler
#![doc(test(a))]
//~^ ERROR unknown `doc(test)` attribute `a`
//~^^ WARN this was previously accepted by the compiler
pub fn foo() {}

View File

@ -1,34 +1,22 @@
error: `#[doc(test(...)]` takes a list of attributes
--> $DIR/doc-test-attr.rs:4:8
--> $DIR/doc-test-attr.rs:3:8
|
LL | #![doc(test)]
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here
--> $DIR/doc-test-attr.rs:2:9
|
LL | #![deny(invalid_doc_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` on by default
error: `#[doc(test(...)]` takes a list of attributes
--> $DIR/doc-test-attr.rs:7:8
--> $DIR/doc-test-attr.rs:5:8
|
LL | #![doc(test = "hello")]
| ^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc(test)` attribute `a`
--> $DIR/doc-test-attr.rs:10:13
--> $DIR/doc-test-attr.rs:7:13
|
LL | #![doc(test(a))]
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: aborting due to 3 previous errors

View File

@ -1,25 +1,17 @@
#![crate_type = "lib"]
#![deny(warnings)]
#![doc(as_ptr)]
//~^ ERROR unknown `doc` attribute
//~^^ WARN
#[doc(as_ptr)]
//~^ ERROR unknown `doc` attribute
//~^^ WARN
pub fn foo() {}
#[doc(123)]
//~^ ERROR invalid `doc` attribute
//~| WARN
#[doc("hello", "bar")]
//~^ ERROR invalid `doc` attribute
//~| WARN
//~| ERROR invalid `doc` attribute
//~| WARN
#[doc(foo::bar, crate::bar::baz = "bye")]
//~^ ERROR unknown `doc` attribute
//~| WARN
//~| ERROR unknown `doc` attribute
//~| WARN
fn bar() {}

View File

@ -1,71 +1,46 @@
error: unknown `doc` attribute `as_ptr`
--> $DIR/doc-attr.rs:7:7
--> $DIR/doc-attr.rs:5:7
|
LL | #[doc(as_ptr)]
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here
--> $DIR/doc-attr.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= note: `#[deny(invalid_doc_attributes)]` on by default
error: invalid `doc` attribute
--> $DIR/doc-attr.rs:12:7
--> $DIR/doc-attr.rs:9:7
|
LL | #[doc(123)]
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: invalid `doc` attribute
--> $DIR/doc-attr.rs:15:7
--> $DIR/doc-attr.rs:11:7
|
LL | #[doc("hello", "bar")]
| ^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: invalid `doc` attribute
--> $DIR/doc-attr.rs:15:16
--> $DIR/doc-attr.rs:11:16
|
LL | #[doc("hello", "bar")]
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc` attribute `foo::bar`
--> $DIR/doc-attr.rs:20:7
--> $DIR/doc-attr.rs:14:7
|
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
| ^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc` attribute `crate::bar::baz`
--> $DIR/doc-attr.rs:20:17
--> $DIR/doc-attr.rs:14:17
|
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc` attribute `as_ptr`
--> $DIR/doc-attr.rs:3:8
--> $DIR/doc-attr.rs:2:8
|
LL | #![doc(as_ptr)]
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: aborting due to 7 previous errors

View File

@ -1,8 +1,6 @@
//@ run-rustfix
#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(notable_trait)]
//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}

View File

@ -1,8 +1,6 @@
//@ run-rustfix
#![deny(warnings)]
#![feature(doc_notable_trait)]
#[doc(spotlight)]
//~^ ERROR unknown `doc` attribute `spotlight`
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
trait MyTrait {}

View File

@ -1,19 +1,12 @@
error: unknown `doc` attribute `spotlight`
--> $DIR/doc-spotlight.rs:5:7
--> $DIR/doc-spotlight.rs:4:7
|
LL | #[doc(spotlight)]
| ^^^^^^^^^ help: use `notable_trait` instead
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `doc(spotlight)` was renamed to `doc(notable_trait)`
= note: `doc(spotlight)` is now a no-op
note: the lint level is defined here
--> $DIR/doc-spotlight.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= note: `#[deny(invalid_doc_attributes)]` on by default
error: aborting due to 1 previous error

View File

@ -1,11 +1,7 @@
#![feature(doc_cfg_hide)]
#![deny(warnings)]
#![doc(cfg_hide = "test")] //~ ERROR
//~^ WARN
#![doc(cfg_hide)] //~ ERROR
//~^ WARN
#[doc(cfg_hide(doc))] //~ ERROR
//~^ WARN
pub fn foo() {}

View File

@ -1,40 +1,27 @@
error: this attribute can only be applied at the crate level
--> $DIR/doc_cfg_hide.rs:9:7
--> $DIR/doc_cfg_hide.rs:6:7
|
LL | #[doc(cfg_hide(doc))]
| ^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
note: the lint level is defined here
--> $DIR/doc_cfg_hide.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= note: `#[deny(invalid_doc_attributes)]` on by default
help: to apply to the crate, use an inner attribute
|
LL | #![doc(cfg_hide(doc))]
| +
error: `#[doc(cfg_hide(...))]` takes a list of attributes
--> $DIR/doc_cfg_hide.rs:4:8
--> $DIR/doc_cfg_hide.rs:3:8
|
LL | #![doc(cfg_hide = "test")]
| ^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: `#[doc(cfg_hide(...))]` takes a list of attributes
--> $DIR/doc_cfg_hide.rs:6:8
--> $DIR/doc_cfg_hide.rs:4:8
|
LL | #![doc(cfg_hide)]
| ^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: aborting due to 3 previous errors

View File

@ -1,32 +1,25 @@
#![crate_type = "lib"]
#![deny(warnings)]
#![feature(doc_masked)]
#![doc(masked)]
//~^ ERROR this attribute can only be applied to an `extern crate` item
//~| WARN is being phased out
#[doc(test(no_crate_inject))]
//~^ ERROR can only be applied at the crate level
//~| WARN is being phased out
//~| HELP to apply to the crate, use an inner attribute
//~| SUGGESTION !
#[doc(inline)]
//~^ ERROR can only be applied to a `use` item
//~| WARN is being phased out
pub fn foo() {}
pub mod bar {
#![doc(test(no_crate_inject))]
//~^ ERROR can only be applied at the crate level
//~| WARN is being phased out
#[doc(test(no_crate_inject))]
//~^ ERROR can only be applied at the crate level
//~| WARN is being phased out
#[doc(inline)]
//~^ ERROR can only be applied to a `use` item
//~| WARN is being phased out
pub fn baz() {}
}
@ -38,10 +31,8 @@ pub fn baz() {}
#[doc(masked)]
//~^ ERROR this attribute can only be applied to an `extern crate` item
//~| WARN is being phased out
pub struct Masked;
#[doc(masked)]
//~^ ERROR this attribute cannot be applied to an `extern crate self` item
//~| WARN is being phased out
pub extern crate self as reexport;

View File

@ -1,48 +1,37 @@
error: this attribute can only be applied at the crate level
--> $DIR/invalid-doc-attr.rs:9:7
--> $DIR/invalid-doc-attr.rs:7:7
|
LL | #[doc(test(no_crate_inject))]
| ^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
note: the lint level is defined here
--> $DIR/invalid-doc-attr.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= note: `#[deny(invalid_doc_attributes)]` on by default
help: to apply to the crate, use an inner attribute
|
LL | #![doc(test(no_crate_inject))]
| +
error: this attribute can only be applied to a `use` item
--> $DIR/invalid-doc-attr.rs:14:7
--> $DIR/invalid-doc-attr.rs:11:7
|
LL | #[doc(inline)]
| ^^^^^^ only applicable on `use` items
...
LL |
LL | pub fn foo() {}
| ------------ not a `use` item
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
error: this attribute can only be applied at the crate level
--> $DIR/invalid-doc-attr.rs:20:12
--> $DIR/invalid-doc-attr.rs:16:12
|
LL | #![doc(test(no_crate_inject))]
| ^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
error: conflicting doc inlining attributes
--> $DIR/invalid-doc-attr.rs:33:7
--> $DIR/invalid-doc-attr.rs:26:7
|
LL | #[doc(inline)]
| ^^^^^^ this attribute...
@ -52,61 +41,50 @@ LL | #[doc(no_inline)]
= help: remove one of the conflicting attributes
error: this attribute can only be applied to an `extern crate` item
--> $DIR/invalid-doc-attr.rs:39:7
--> $DIR/invalid-doc-attr.rs:32:7
|
LL | #[doc(masked)]
| ^^^^^^ only applicable on `extern crate` items
...
LL |
LL | pub struct Masked;
| ----------------- not an `extern crate` item
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
error: this attribute cannot be applied to an `extern crate self` item
--> $DIR/invalid-doc-attr.rs:44:7
--> $DIR/invalid-doc-attr.rs:36:7
|
LL | #[doc(masked)]
| ^^^^^^ not applicable on `extern crate self` items
...
LL |
LL | pub extern crate self as reexport;
| --------------------------------- `extern crate self` defined here
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: this attribute can only be applied to an `extern crate` item
--> $DIR/invalid-doc-attr.rs:5:8
--> $DIR/invalid-doc-attr.rs:4:8
|
LL | #![doc(masked)]
| ^^^^^^ only applicable on `extern crate` items
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
error: this attribute can only be applied at the crate level
--> $DIR/invalid-doc-attr.rs:24:11
--> $DIR/invalid-doc-attr.rs:19:11
|
LL | #[doc(test(no_crate_inject))]
| ^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
error: this attribute can only be applied to a `use` item
--> $DIR/invalid-doc-attr.rs:27:11
--> $DIR/invalid-doc-attr.rs:21:11
|
LL | #[doc(inline)]
| ^^^^^^ only applicable on `use` items
...
LL |
LL | pub fn baz() {}
| ------------ not a `use` item
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
error: aborting due to 9 previous errors

View File

@ -19,8 +19,12 @@
extern crate stable_mir;
use rustc_smir::rustc_internal;
use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
use stable_mir::abi::{
ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
VariantsShape,
};
use stable_mir::mir::mono::Instance;
use stable_mir::target::MachineInfo;
use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
use std::assert_matches::assert_matches;
use std::convert::TryFrom;
@ -39,11 +43,12 @@ fn test_stable_mir() -> ControlFlow<()> {
let instance = Instance::try_from(target_fn).unwrap();
let fn_abi = instance.fn_abi().unwrap();
assert_eq!(fn_abi.conv, CallConvention::Rust);
assert_eq!(fn_abi.args.len(), 2);
assert_eq!(fn_abi.args.len(), 3);
check_ignore(&fn_abi.args[0]);
check_primitive(&fn_abi.args[1]);
check_result(fn_abi.ret);
check_niche(&fn_abi.args[2]);
check_result(&fn_abi.ret);
// Test variadic function.
let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
@ -85,7 +90,7 @@ fn check_primitive(abi: &ArgAbi) {
}
/// Check the return value: `Result<usize, &str>`.
fn check_result(abi: ArgAbi) {
fn check_result(abi: &ArgAbi) {
assert!(abi.ty.kind().is_enum());
assert_matches!(abi.mode, PassMode::Indirect { .. });
let layout = abi.layout.shape();
@ -94,6 +99,25 @@ fn check_result(abi: ArgAbi) {
assert_matches!(layout.variants, VariantsShape::Multiple { .. })
}
/// Check the niche information about: `NonZeroU8`
fn check_niche(abi: &ArgAbi) {
assert!(abi.ty.kind().is_struct());
assert_matches!(abi.mode, PassMode::Direct { .. });
let layout = abi.layout.shape();
assert!(layout.is_sized());
assert_eq!(layout.size.bytes(), 1);
let ValueAbi::Scalar(scalar) = layout.abi else { unreachable!() };
assert!(scalar.has_niche(&MachineInfo::target()), "Opps: {:?}", scalar);
let Scalar::Initialized { value, valid_range } = scalar else { unreachable!() };
assert_matches!(value, Primitive::Int { length: IntegerLength::I8, signed: false });
assert_eq!(valid_range.start, 1);
assert_eq!(valid_range.end, u8::MAX.into());
assert!(!valid_range.contains(0));
assert!(!valid_range.wraps_around());
}
fn get_item<'a>(
items: &'a CrateItems,
item: (ItemKind, &str),
@ -126,11 +150,16 @@ fn generate_input(path: &str) -> std::io::Result<()> {
#![feature(c_variadic)]
#![allow(unused_variables)]
pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
// We only care about the signature.
todo!()
}}
use std::num::NonZeroU8;
pub fn fn_abi(
ignore: [u8; 0],
primitive: char,
niche: NonZeroU8,
) -> Result<usize, &'static str> {{
// We only care about the signature.
todo!()
}}
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
0

View File

@ -55,7 +55,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
LL | foo::<Demo>()();
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
|
= help: the trait `TraitWAssocConst` is implemented for `{type error}`
note: required by a bound in `foo`
--> $DIR/issue-105330.rs:11:11
|
@ -92,7 +91,6 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
LL | foo::<Demo>();
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
|
= help: the trait `TraitWAssocConst` is implemented for `{type error}`
note: required by a bound in `foo`
--> $DIR/issue-105330.rs:11:11
|

View File

@ -21,7 +21,6 @@ impl Grault for () {
impl<T: Grault> Grault for (T,)
//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
{
type A = ();
type B = bool;

View File

@ -1,25 +1,17 @@
#![crate_type = "lib"]
#![deny(warnings)]
#![doc(as_ptr)]
//~^ ERROR unknown `doc` attribute
//~^^ WARN
#[doc(as_ptr)]
//~^ ERROR unknown `doc` attribute
//~^^ WARN
pub fn foo() {}
#[doc(123)]
//~^ ERROR invalid `doc` attribute
//~| WARN
#[doc("hello", "bar")]
//~^ ERROR invalid `doc` attribute
//~| WARN
//~| ERROR invalid `doc` attribute
//~| WARN
#[doc(foo::bar, crate::bar::baz = "bye")]
//~^ ERROR unknown `doc` attribute
//~| WARN
//~| ERROR unknown `doc` attribute
//~| WARN
fn bar() {}

View File

@ -1,71 +1,46 @@
error: unknown `doc` attribute `as_ptr`
--> $DIR/doc-attr.rs:7:7
--> $DIR/doc-attr.rs:5:7
|
LL | #[doc(as_ptr)]
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here
--> $DIR/doc-attr.rs:2:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= note: `#[deny(invalid_doc_attributes)]` on by default
error: invalid `doc` attribute
--> $DIR/doc-attr.rs:12:7
--> $DIR/doc-attr.rs:9:7
|
LL | #[doc(123)]
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: invalid `doc` attribute
--> $DIR/doc-attr.rs:15:7
--> $DIR/doc-attr.rs:11:7
|
LL | #[doc("hello", "bar")]
| ^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: invalid `doc` attribute
--> $DIR/doc-attr.rs:15:16
--> $DIR/doc-attr.rs:11:16
|
LL | #[doc("hello", "bar")]
| ^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc` attribute `foo::bar`
--> $DIR/doc-attr.rs:20:7
--> $DIR/doc-attr.rs:14:7
|
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
| ^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc` attribute `crate::bar::baz`
--> $DIR/doc-attr.rs:20:17
--> $DIR/doc-attr.rs:14:17
|
LL | #[doc(foo::bar, crate::bar::baz = "bye")]
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc` attribute `as_ptr`
--> $DIR/doc-attr.rs:3:8
--> $DIR/doc-attr.rs:2:8
|
LL | #![doc(as_ptr)]
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: aborting due to 7 previous errors

View File

@ -1,7 +1,4 @@
#![deny(warnings)]
#![doc(test(""))]
//~^ ERROR `#![doc(test(...)]` does not take a literal
//~^^ WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
fn main() {}

View File

@ -1,17 +1,10 @@
error: `#![doc(test(...)]` does not take a literal
--> $DIR/doc-test-literal.rs:3:13
--> $DIR/doc-test-literal.rs:1:13
|
LL | #![doc(test(""))]
| ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here
--> $DIR/doc-test-literal.rs:1:9
|
LL | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]`
= note: `#[deny(invalid_doc_attributes)]` on by default
error: aborting due to 1 previous error

View File

@ -11,8 +11,7 @@ fn f(u8) {} //~ WARN anonymous parameters are deprecated
pub mod submodule {
// Error since this is a `future_incompatible` lint
#![doc(test(some_test))]
//~^ ERROR this attribute can only be applied at the crate level
//~| WARN this was previously accepted by the compiler
//~^ ERROR this attribute can only be applied at the crate level
}
fn main() {}

View File

@ -14,15 +14,8 @@ error: this attribute can only be applied at the crate level
LL | #![doc(test(some_test))]
| ^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
note: the lint level is defined here
--> $DIR/future-incompatible-lint-group.rs:3:9
|
LL | #![deny(future_incompatible)]
| ^^^^^^^^^^^^^^^^^^^
= note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(future_incompatible)]`
= note: `#[deny(invalid_doc_attributes)]` on by default
error: aborting due to 1 previous error; 1 warning emitted

View File

@ -2,10 +2,8 @@
#![allow(dead_code)]
#![deny(no_mangle_generic_items)]
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
pub extern "C" fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
#[no_mangle]

View File

@ -4,7 +4,6 @@ error[E0275]: overflow evaluating the requirement `for<'a> &'a mut Bar well-form
LL | for<'a> &'a mut Self:;
| ^^^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`)
note: required by a bound in `Bar`
--> $DIR/issue-95230.rs:9:13
|

View File

@ -27,10 +27,8 @@ use issue_52891::{l,
use issue_52891::a::inner;
use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times
//~^ ERROR `issue_52891` is defined multiple times
#[macro_use]
use issue_52891::n; //~ ERROR `n` is defined multiple times

View File

@ -2,7 +2,6 @@
#![deny(unused_imports)]
// Check that attributes get removed too. See #87973.
//~^ ERROR unused import
fn main() {}

View 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() {}

View 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`.

View File

@ -3,8 +3,6 @@ error[E0275]: overflow evaluating the requirement `Loop == _`
|
LL | impl Loop {}
| ^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)
error[E0392]: type parameter `T` is never used
--> $DIR/inherent-impls-overflow.rs:13:12

View File

@ -7,11 +7,9 @@
// Check that we *reject* leading where-clauses on lazy type aliases.
pub type Leading0<T>
= T where String: From<T>;
pub type Leading1<T, U>
= (T, U)
where
U: Copy, String: From<T>;

View File

@ -7,7 +7,6 @@
//~^ ERROR const items should never be `#[no_mangle]`
//~| HELP try a static value
//~^ HELP remove this attribute
pub fn defiant<T>(_t: T) {}
//~^ WARN functions generic over types or consts must be mangled

View 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

View 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

View 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

View File

@ -17,6 +17,5 @@ pub enum OwO4 {
}
#[repr(uwu)] //~ERROR: unrecognized representation hint
#[doc(owo)] //~WARN: unknown `doc` attribute
//~^ WARN: this was previously
#[doc(owo)] //~ERROR: unknown `doc` attribute
pub struct Owo5;

View File

@ -30,15 +30,13 @@ LL | #[repr(uwu, u8)]
|
= help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
warning: unknown `doc` attribute `owo`
error: unknown `doc` attribute `owo`
--> $DIR/invalid_repr_list_help.rs:20:7
|
LL | #[doc(owo)]
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
= note: `#[warn(invalid_doc_attributes)]` on by default
= note: `#[deny(invalid_doc_attributes)]` on by default
error[E0552]: unrecognized representation hint
--> $DIR/invalid_repr_list_help.rs:19:8
@ -48,6 +46,6 @@ LL | #[repr(uwu)]
|
= help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
error: aborting due to 5 previous errors; 1 warning emitted
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0552`.

View File

@ -2,7 +2,6 @@
#[allow(unused_imports)]
use std::mem::transmute;
//~^ ERROR the name `transmute` is defined multiple times
fn main() {

View File

@ -9,7 +9,6 @@
#![deny(rust_2018_idioms)]
#![allow(dead_code)]
//~^ ERROR unused extern crate
// Shouldn't suggest changing to `use`, as `bar`

View File

@ -8,7 +8,6 @@
// The suggestion span should include the attribute.
//~^ ERROR unused extern crate
fn main() {}

View File

@ -2,6 +2,4 @@
//~^ NOTE defined here
#![doc(x)]
//~^ ERROR unknown `doc` attribute `x`
//~| WARNING will become a hard error
//~| NOTE see issue #82730
fn main() {}

View File

@ -4,8 +4,6 @@ error: unknown `doc` attribute `x`
LL | #![doc(x)]
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here
--> $DIR/deny-invalid-doc-attrs.rs:1:9
|

View File

@ -2,7 +2,6 @@
#[doc(primitive = "foo")]
//~^ ERROR unknown `doc` attribute `primitive`
//~| WARN
mod bar {}
fn main() {}

View File

@ -4,8 +4,6 @@ error: unknown `doc` attribute `primitive`
LL | #[doc(primitive = "foo")]
| ^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here
--> $DIR/doc-primitive.rs:1:9
|

View File

@ -3,12 +3,9 @@
#![doc(test)]
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
//~^^ WARN this was previously accepted by the compiler
#![doc(test = "hello")]
//~^ ERROR `#[doc(test(...)]` takes a list of attributes
//~^^ WARN this was previously accepted by the compiler
#![doc(test(a))]
//~^ ERROR unknown `doc(test)` attribute `a`
//~^^ WARN this was previously accepted by the compiler
pub fn foo() {}

View File

@ -4,8 +4,6 @@ error: `#[doc(test(...)]` takes a list of attributes
LL | #![doc(test)]
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
note: the lint level is defined here
--> $DIR/doc-test-attr.rs:2:9
|
@ -13,22 +11,16 @@ LL | #![deny(invalid_doc_attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: `#[doc(test(...)]` takes a list of attributes
--> $DIR/doc-test-attr.rs:7:8
--> $DIR/doc-test-attr.rs:6:8
|
LL | #![doc(test = "hello")]
| ^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: unknown `doc(test)` attribute `a`
--> $DIR/doc-test-attr.rs:10:13
--> $DIR/doc-test-attr.rs:8:13
|
LL | #![doc(test(a))]
| ^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82730 <https://github.com/rust-lang/rust/issues/82730>
error: aborting due to 3 previous errors

View File

@ -1,5 +1,5 @@
error: malformed `cfi_encoding` attribute input
--> $DIR/sanitizer-cfi-invalid-attr-cfi-encoding.rs:10:1
--> $DIR/cfi-invalid-attr-cfi-encoding.rs:10:1
|
LL | #[cfi_encoding]
| ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]`

Some files were not shown because too many files have changed in this diff Show More