1
Fork 0

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 @@ impl<'a> Linker for AixLinker<'a> {
fn optimize(&mut self) {} fn optimize(&mut self) {}
fn pgo_gen(&mut self) {} fn pgo_gen(&mut self) {
self.cmd.arg("-bdbg:namedsects:ss");
}
fn control_flow_guard(&mut self) {} fn control_flow_guard(&mut self) {}

View file

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

View file

@ -1744,7 +1744,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Ty::new_unit(self.tcx), Ty::new_unit(self.tcx),
); );
} }
if !self.consider_removing_semicolon(blk, expected_ty, err) { if !self.err_ctxt().consider_removing_semicolon(
blk,
expected_ty,
err,
) {
self.err_ctxt().consider_returning_binding( self.err_ctxt().consider_returning_binding(
blk, blk,
expected_ty, expected_ty,

View file

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

View file

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

View file

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

View file

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

View file

@ -47,8 +47,10 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
ConstEquateError(ref a, ref b) => { ConstEquateError(ref a, ref b) => {
write!(f, "CodeConstEquateError({a:?}, {b:?})") write!(f, "CodeConstEquateError({a:?}, {b:?})")
} }
Ambiguity { overflow: false } => write!(f, "Ambiguity"), Ambiguity { overflow: None } => write!(f, "Ambiguity"),
Ambiguity { overflow: true } => write!(f, "Overflow"), Ambiguity { overflow: Some(suggest_increasing_limit) } => {
write!(f, "Overflow({suggest_increasing_limit})")
}
Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"), Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"),
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -36,11 +36,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
let Some(lhs) = self.try_normalize_term(param_env, lhs)? else { let Some(lhs) = self.try_normalize_term(param_env, lhs)? else {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); return self
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
}; };
let Some(rhs) = self.try_normalize_term(param_env, rhs)? else { let Some(rhs) = self.try_normalize_term(param_env, rhs)? else {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::OVERFLOW); return self
.evaluate_added_goals_and_make_canonical_response(Certainty::overflow(true));
}; };
let variance = match direction { let variance = match direction {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -103,6 +103,7 @@ impl<'tcx> Children {
self_ty: self_ty.has_concrete_skeleton().then_some(self_ty), self_ty: self_ty.has_concrete_skeleton().then_some(self_ty),
intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes,
involves_placeholder: overlap.involves_placeholder, involves_placeholder: overlap.involves_placeholder,
overflowing_predicates: overlap.overflowing_predicates,
} }
}; };

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,7 +4,6 @@
use core; use core;
use serde as edres; use serde as edres;
pub use serde; 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-2.rs",
"ui/rust-2018/uniform-paths/issue-56596.rs", "ui/rust-2018/uniform-paths/issue-56596.rs",
"ui/rust-2018/uniform-paths/issue-87932.rs", "ui/rust-2018/uniform-paths/issue-87932.rs",
"ui/sanitize/issue-111184-coroutine-witness.rs", "ui/sanitizer/issue-111184-cfi-coroutine-witness.rs",
"ui/sanitize/issue-114275-cfi-const-expr-in-arry-len.rs", "ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs",
"ui/sanitize/issue-72154-lifetime-markers.rs", "ui/sanitizer/issue-72154-address-lifetime-markers.rs",
"ui/self/issue-61882-2.rs", "ui/self/issue-61882-2.rs",
"ui/self/issue-61882.rs", "ui/self/issue-61882.rs",
"ui/simd/intrinsic/issue-85855.rs", "ui/simd/intrinsic/issue-85855.rs",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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:; LL | for<'a> &'a mut Self:;
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
| |
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_95230`)
note: required by a bound in `Bar` note: required by a bound in `Bar`
--> $DIR/issue-95230.rs:9:13 --> $DIR/issue-95230.rs:9:13
| |

View file

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

View file

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

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 {} LL | impl Loop {}
| ^^^^ | ^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`inherent_impls_overflow`)
error[E0392]: type parameter `T` is never used error[E0392]: type parameter `T` is never used
--> $DIR/inherent-impls-overflow.rs:13:12 --> $DIR/inherent-impls-overflow.rs:13:12

View file

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

View file

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

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 #[repr(uwu)] //~ERROR: unrecognized representation hint
#[doc(owo)] //~WARN: unknown `doc` attribute #[doc(owo)] //~ERROR: unknown `doc` attribute
//~^ WARN: this was previously
pub struct Owo5; pub struct Owo5;

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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