Auto merge of #120620 - matthiaskrgr:rollup-sscmbsm, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #119543 (add avx512fp16 to x86 target features)
 - #120004 (Release notes for 1.76)
 - #120562 (Revert unsound libcore changes)
 - #120566 (coverage: Use normal `edition:` headers in coverage tests)
 - #120570 (Suggest changing type to const parameters if we encounter a type in the trait bound position)
 - #120571 (Miscellaneous diagnostics cleanups)
 - #120573 (Remove `BorrowckErrors::tainted_by_errors`)
 - #120592 (Remove unnecessary `.to_string()`/`.as_str()`s)
 - #120610 (hir: Remove the generic type parameter from `MaybeOwned`)
 - #120616 (Fix ICE on field access on a tainted type after const-eval failure)

Failed merges:

 - #120569 (coverage: Improve handling of function/closure spans)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-04 18:51:28 +00:00
commit 4e3eed4892
80 changed files with 725 additions and 797 deletions

View File

@ -1,3 +1,96 @@
Version 1.76.0 (2024-02-08)
==========================
<a id="1.76.0-Language"></a>
Language
--------
- [Document Rust ABI compatibility between various types](https://github.com/rust-lang/rust/pull/115476/)
- [Also: guarantee that char and u32 are ABI-compatible](https://github.com/rust-lang/rust/pull/118032/)
- [Warn against ambiguous wide pointer comparisons](https://github.com/rust-lang/rust/pull/117758/)
<a id="1.76.0-Compiler"></a>
Compiler
--------
- [Lint pinned `#[must_use]` pointers (in particular, `Box<T>` where `T` is `#[must_use]`) in `unused_must_use`.](https://github.com/rust-lang/rust/pull/118054/)
- [Soundness fix: fix computing the offset of an unsized field in a packed struct](https://github.com/rust-lang/rust/pull/118540/)
- [Soundness fix: fix dynamic size/align computation logic for packed types with dyn Trait tail](https://github.com/rust-lang/rust/pull/118538/)
- [Add `$message_type` field to distinguish json diagnostic outputs](https://github.com/rust-lang/rust/pull/115691/)
- [Enable Rust to use the EHCont security feature of Windows](https://github.com/rust-lang/rust/pull/118013/)
- [Add tier 3 {x86_64,i686}-win7-windows-msvc targets](https://github.com/rust-lang/rust/pull/118150/)
- [Add tier 3 aarch64-apple-watchos target](https://github.com/rust-lang/rust/pull/119074/)
- [Add tier 3 arm64e-apple-ios & arm64e-apple-darwin targets](https://github.com/rust-lang/rust/pull/115526/)
Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.
<a id="1.76.0-Libraries"></a>
Libraries
---------
- [Add a column number to `dbg!()`](https://github.com/rust-lang/rust/pull/114962/)
- [Add `std::hash::{DefaultHasher, RandomState}` exports](https://github.com/rust-lang/rust/pull/115694/)
- [Fix rounding issue with exponents in fmt](https://github.com/rust-lang/rust/pull/116301/)
- [Add T: ?Sized to `RwLockReadGuard` and `RwLockWriteGuard`'s Debug impls.](https://github.com/rust-lang/rust/pull/117138/)
- [Windows: Allow `File::create` to work on hidden files](https://github.com/rust-lang/rust/pull/116438/)
<a id="1.76.0-Stabilized-APIs"></a>
Stabilized APIs
---------------
- [`Arc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.unwrap_or_clone)
- [`Rc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.unwrap_or_clone)
- [`Result::inspect`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect)
- [`Result::inspect_err`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect_err)
- [`Option::inspect`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.inspect)
- [`type_name_of_val`](https://doc.rust-lang.org/stable/std/any/fn.type_name_of_val.html)
- [`std::hash::{DefaultHasher, RandomState}`](https://doc.rust-lang.org/stable/std/hash/index.html#structs)
These were previously available only through `std::collections::hash_map`.
- [`ptr::{from_ref, from_mut}`](https://doc.rust-lang.org/stable/std/ptr/fn.from_ref.html)
- [`ptr::addr_eq`](https://doc.rust-lang.org/stable/std/ptr/fn.addr_eq.html)
<a id="1.76.0-Cargo"></a>
Cargo
-----
See [Cargo release notes](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-176-2024-02-08).
<a id="1.76.0-Rustdoc"></a>
Rustdoc
-------
- [Don't merge cfg and doc(cfg) attributes for re-exports](https://github.com/rust-lang/rust/pull/113091/)
- [rustdoc: allow resizing the sidebar / hiding the top bar](https://github.com/rust-lang/rust/pull/115660/)
- [rustdoc-search: add support for traits and associated types](https://github.com/rust-lang/rust/pull/116085/)
- [rustdoc: Add highlighting for comments in items declaration](https://github.com/rust-lang/rust/pull/117869/)
<a id="1.76.0-Compatibility-Notes"></a>
Compatibility Notes
-------------------
- [Add allow-by-default lint for unit bindings](https://github.com/rust-lang/rust/pull/112380/)
This is expected to be upgraded to a warning by default in a future Rust
release. Some macros emit bindings with type `()` with user-provided spans,
which means that this lint will warn for user code.
- [Remove x86_64-sun-solaris target.](https://github.com/rust-lang/rust/pull/118091/)
- [Remove asmjs-unknown-emscripten target](https://github.com/rust-lang/rust/pull/117338/)
- [Report errors in jobserver inherited through environment variables](https://github.com/rust-lang/rust/pull/113730/)
This [may warn](https://github.com/rust-lang/rust/issues/120515) on benign problems too.
- [Update the minimum external LLVM to 16.](https://github.com/rust-lang/rust/pull/117947/)
- [Improve `print_tts`](https://github.com/rust-lang/rust/pull/114571/)
This change can break some naive manual parsing of token trees in proc macro
code which expect a particular structure after `.to_string()`, rather than just arbitrary Rust code.
- [Make `IMPLIED_BOUNDS_ENTAILMENT` into a hard error from a lint](https://github.com/rust-lang/rust/pull/117984/)
- [Vec's allocation behavior was changed when collecting some iterators](https://github.com/rust-lang/rust/pull/110353)
Allocation behavior is currently not specified, nevertheless changes can be surprising.
See [`impl FromIterator for Vec`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#impl-FromIterator%3CT%3E-for-Vec%3CT%3E)
for more details.
- [Properly reject `default` on free const items](https://github.com/rust-lang/rust/pull/117818/)
Version 1.75.0 (2023-12-28)
==========================

View File

@ -25,7 +25,7 @@ pub(super) struct ItemLowerer<'a, 'hir> {
pub(super) tcx: TyCtxt<'hir>,
pub(super) resolver: &'a mut ResolverAstLowering,
pub(super) ast_index: &'a IndexSlice<LocalDefId, AstOwner<'a>>,
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<'hir>>,
}
/// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span
@ -64,10 +64,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
}
}
pub(super) fn lower_node(
&mut self,
def_id: LocalDefId,
) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> {
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
if let hir::MaybeOwner::Phantom = owner {
let node = self.ast_index[def_id];

View File

@ -99,7 +99,7 @@ struct LoweringContext<'a, 'hir> {
/// Attributes inside the owner being lowered.
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
/// Collect items that were created by lowering the current owner.
children: Vec<(LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>)>,
children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>,
coroutine_kind: Option<hir::CoroutineKind>,
@ -415,7 +415,7 @@ fn index_crate<'a>(
/// This hash will then be part of the crate_hash which is stored in the metadata.
fn compute_hir_hash(
tcx: TyCtxt<'_>,
owners: &IndexSlice<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
owners: &IndexSlice<LocalDefId, hir::MaybeOwner<'_>>,
) -> Fingerprint {
let mut hir_body_nodes: Vec<_> = owners
.iter_enumerated()

View File

@ -130,7 +130,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
noun_old: &str,
old_opt_via: &str,
previous_end_span: Option<Span>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_code_err!(
self.dcx(),
new_loan_span,
@ -162,7 +162,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
old_opt_via: &str,
previous_end_span: Option<Span>,
second_borrow_desc: &str,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_code_err!(
self.dcx(),
new_loan_span,
@ -194,7 +194,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
kind_old: &str,
msg_old: &str,
old_load_end_span: Option<Span>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
let mut err = struct_span_code_err!(
self.dcx(),
@ -235,7 +235,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
span: Span,
borrow_span: Span,
desc: &str,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
struct_span_code_err!(
self.dcx(),
span,
@ -252,7 +252,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
span: Span,
desc: &str,
is_arg: bool,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc)
}
@ -265,7 +265,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
&self,
move_from_span: Span,
move_from_desc: &str,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
struct_span_code_err!(
self.dcx(),
move_from_span,
@ -283,7 +283,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
move_from_span: Span,
ty: Ty<'_>,
is_index: Option<bool>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let type_name = match (&ty.kind(), is_index) {
(&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
(&ty::Slice(_), _) => "slice",
@ -304,7 +304,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
&self,
move_from_span: Span,
container_ty: Ty<'_>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
struct_span_code_err!(
self.dcx(),
move_from_span,

View File

@ -327,7 +327,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&mut self,
mpi: MovePathIndex,
move_span: Span,
err: &mut DiagnosticBuilder<'_>,
err: &mut DiagnosticBuilder<'tcx>,
in_pattern: &mut bool,
move_spans: UseSpans<'_>,
) {
@ -486,7 +486,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
desired_action: InitializationRequiringAction,
span: Span,
use_spans: UseSpans<'tcx>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
// We need all statements in the body where the binding was assigned to later find all
// the branching code paths where the binding *wasn't* assigned to.
let inits = &self.move_data.init_path_map[mpi];
@ -880,7 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
location: Location,
(place, _span): (Place<'tcx>, Span),
borrow: &BorrowData<'tcx>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let borrow_spans = self.retrieve_borrow_spans(borrow);
let borrow_span = borrow_spans.args_or_use();
@ -930,7 +930,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(place, span): (Place<'tcx>, Span),
gen_borrow_kind: BorrowKind,
issued_borrow: &BorrowData<'tcx>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let issued_spans = self.retrieve_borrow_spans(issued_borrow);
let issued_span = issued_spans.args_or_use();
@ -2129,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
drop_span: Span,
borrow_spans: UseSpans<'tcx>,
explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
debug!(
"report_local_value_does_not_live_long_enough(\
{:?}, {:?}, {:?}, {:?}, {:?}\
@ -2304,7 +2304,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&mut self,
drop_span: Span,
borrow_span: Span,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
debug!(
"report_thread_local_value_does_not_live_long_enough(\
{:?}, {:?}\
@ -2329,7 +2329,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_spans: UseSpans<'tcx>,
proper_span: Span,
explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
explanation
{
@ -2440,7 +2440,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"consider consuming the `{ty}` when turning it into an \
`Iterator`",
),
"into_iter".to_string(),
"into_iter",
Applicability::MaybeIncorrect,
);
}
@ -2496,7 +2496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
return_span: Span,
category: ConstraintCategory<'tcx>,
opt_place_desc: Option<&String>,
) -> Option<DiagnosticBuilder<'cx>> {
) -> Option<DiagnosticBuilder<'tcx>> {
let return_kind = match category {
ConstraintCategory::Return(_) => "return",
ConstraintCategory::Yield => "yield",
@ -2591,7 +2591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
constraint_span: Span,
captured_var: &str,
scope: &str,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use();
@ -2699,7 +2699,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
upvar_span: Span,
upvar_name: Symbol,
escape_span: Span,
) -> DiagnosticBuilder<'cx> {
) -> DiagnosticBuilder<'tcx> {
let tcx = self.infcx.tcx;
let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id());

View File

@ -288,7 +288,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&mut self,
place: Place<'tcx>,
span: Span,
) -> DiagnosticBuilder<'a> {
) -> DiagnosticBuilder<'tcx> {
let description = if place.projection.len() == 1 {
format!("static item {}", self.describe_any_place(place.as_ref()))
} else {
@ -310,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
deref_target_place: Place<'tcx>,
span: Span,
use_spans: Option<UseSpans<'tcx>>,
) -> DiagnosticBuilder<'a> {
) -> DiagnosticBuilder<'tcx> {
// Inspect the type of the content behind the
// borrow to provide feedback about why this
// was a move rather than a copy.

View File

@ -198,12 +198,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
{
let span = self.body.local_decls[local].source_info.span;
mut_error = Some(span);
if let Some((buffer, c)) = self.get_buffered_mut_error(span) {
if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) {
// We've encountered a second (or more) attempt to mutably borrow an
// immutable binding, so the likely problem is with the binding
// declaration, not the use. We collect these in a single diagnostic
// and make the binding the primary span of the error.
err = buffer;
err = buffered_err;
count = c + 1;
if count == 2 {
err.replace_span_with(span, false);
@ -924,7 +924,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
expr.span.shrink_to_lo(),
"use a mutable iterator instead",
"mut ".to_string(),
"mut ",
Applicability::MachineApplicable,
);
}

View File

@ -251,6 +251,6 @@ impl OutlivesSuggestionBuilder {
diag.sort_span = mir_span.shrink_to_hi();
// Buffer the diagnostic
mbcx.buffer_non_error_diag(diag);
mbcx.buffer_non_error(diag);
}
}

View File

@ -19,7 +19,7 @@ extern crate tracing;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_errors::{Diagnostic, DiagnosticBuilder};
use rustc_errors::DiagnosticBuilder;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
@ -173,12 +173,11 @@ fn do_mir_borrowck<'tcx>(
}
}
let mut errors = error::BorrowckErrors::new(infcx.tcx);
let mut diags = diags::BorrowckDiags::new();
// Gather the upvars of a closure, if any.
if let Some(e) = input_body.tainted_by_errors {
infcx.set_tainted_by_errors(e);
errors.set_tainted_by_errors(e);
}
// Replace all regions with fresh inference variables. This
@ -244,7 +243,7 @@ fn do_mir_borrowck<'tcx>(
&regioncx,
&opt_closure_req,
&opaque_type_values,
&mut errors,
&mut diags,
);
// The various `flow_*` structures can be large. We drop `flow_inits` here
@ -305,11 +304,11 @@ fn do_mir_borrowck<'tcx>(
next_region_name: RefCell::new(1),
polonius_output: None,
move_errors: Vec::new(),
errors,
diags,
};
MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body);
promoted_mbcx.report_move_errors();
errors = promoted_mbcx.errors;
diags = promoted_mbcx.diags;
struct MoveVisitor<'a, 'cx, 'tcx> {
ctxt: &'a mut MirBorrowckCtxt<'cx, 'tcx>,
@ -346,7 +345,7 @@ fn do_mir_borrowck<'tcx>(
next_region_name: RefCell::new(1),
polonius_output,
move_errors: Vec::new(),
errors,
diags,
};
// Compute and report region errors, if any.
@ -574,7 +573,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
/// Results of Polonius analysis.
polonius_output: Option<Rc<PoloniusOutput>>,
errors: error::BorrowckErrors<'tcx>,
diags: diags::BorrowckDiags<'tcx>,
move_errors: Vec<MoveError<'tcx>>,
}
@ -2125,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
| WriteKind::MutableBorrow(BorrowKind::Fake),
) => {
if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
&& !self.has_buffered_errors()
&& !self.has_buffered_diags()
{
// rust-lang/rust#46908: In pure NLL mode this code path should be
// unreachable, but we use `span_delayed_bug` because we can hit this when
@ -2383,17 +2382,30 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
mod error {
mod diags {
use rustc_errors::ErrorGuaranteed;
use super::*;
pub struct BorrowckErrors<'tcx> {
tcx: TyCtxt<'tcx>,
enum BufferedDiag<'tcx> {
Error(DiagnosticBuilder<'tcx>),
NonError(DiagnosticBuilder<'tcx, ()>),
}
impl<'tcx> BufferedDiag<'tcx> {
fn sort_span(&self) -> Span {
match self {
BufferedDiag::Error(diag) => diag.sort_span,
BufferedDiag::NonError(diag) => diag.sort_span,
}
}
}
pub struct BorrowckDiags<'tcx> {
/// This field keeps track of move errors that are to be reported for given move indices.
///
/// There are situations where many errors can be reported for a single move out (see #53807)
/// and we want only the best of those errors.
/// There are situations where many errors can be reported for a single move out (see
/// #53807) and we want only the best of those errors.
///
/// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
/// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of
@ -2406,51 +2418,38 @@ mod error {
/// same primary span come out in a consistent order.
buffered_move_errors:
BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx>, usize)>,
/// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder`
/// because it has a mixture of error diagnostics and non-error diagnostics.
buffered: Vec<Diagnostic>,
/// Set to Some if we emit an error during borrowck
tainted_by_errors: Option<ErrorGuaranteed>,
/// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics.
buffered_diags: Vec<BufferedDiag<'tcx>>,
}
impl<'tcx> BorrowckErrors<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
BorrowckErrors {
tcx,
impl<'tcx> BorrowckDiags<'tcx> {
pub fn new() -> Self {
BorrowckDiags {
buffered_move_errors: BTreeMap::new(),
buffered_mut_errors: Default::default(),
buffered: Default::default(),
tainted_by_errors: None,
buffered_diags: Default::default(),
}
}
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
if let None = self.tainted_by_errors {
self.tainted_by_errors = Some(self.tcx.dcx().span_delayed_bug(
t.span.clone_ignoring_labels(),
"diagnostic buffered but not emitted",
))
}
self.buffered.push(t.into_diagnostic());
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) {
self.buffered_diags.push(BufferedDiag::Error(t));
}
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
self.buffered.push(t.into_diagnostic());
}
pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) {
self.tainted_by_errors = Some(e);
pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) {
self.buffered_diags.push(BufferedDiag::NonError(t));
}
}
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
self.errors.buffer_error(t);
pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) {
self.diags.buffer_error(t);
}
pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) {
self.errors.buffer_non_error_diag(t);
pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) {
self.diags.buffer_non_error(t);
}
pub fn buffer_move_error(
@ -2459,7 +2458,7 @@ mod error {
place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
) -> bool {
if let Some((_, diag)) =
self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
self.diags.buffered_move_errors.insert(move_out_indices, place_and_err)
{
// Cancel the old diagnostic so we don't ICE
diag.cancel();
@ -2473,47 +2472,50 @@ mod error {
&mut self,
span: Span,
) -> Option<(DiagnosticBuilder<'tcx>, usize)> {
self.errors.buffered_mut_errors.remove(&span)
self.diags.buffered_mut_errors.remove(&span)
}
pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) {
self.errors.buffered_mut_errors.insert(span, (t, count));
self.diags.buffered_mut_errors.insert(span, (t, count));
}
pub fn emit_errors(&mut self) -> Option<ErrorGuaranteed> {
let mut res = None;
// Buffer any move errors that we collected and de-duplicated.
for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) {
for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) {
// We have already set tainted for this error, so just buffer it.
self.errors.buffered.push(diag.into_diagnostic());
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
}
for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) {
if count > 10 {
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
}
self.errors.buffered.push(diag.into_diagnostic());
self.diags.buffered_diags.push(BufferedDiag::Error(diag));
}
if !self.errors.buffered.is_empty() {
self.errors.buffered.sort_by_key(|diag| diag.sort_span);
let dcx = self.dcx();
for diag in self.errors.buffered.drain(..) {
dcx.emit_diagnostic(diag);
if !self.diags.buffered_diags.is_empty() {
self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span());
for buffered_diag in self.diags.buffered_diags.drain(..) {
match buffered_diag {
BufferedDiag::Error(diag) => res = Some(diag.emit()),
BufferedDiag::NonError(diag) => diag.emit(),
}
}
}
self.errors.tainted_by_errors
res
}
pub fn has_buffered_errors(&self) -> bool {
self.errors.buffered.is_empty()
pub(crate) fn has_buffered_diags(&self) -> bool {
self.diags.buffered_diags.is_empty()
}
pub fn has_move_error(
&self,
move_out_indices: &[MoveOutIndex],
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
self.errors.buffered_move_errors.get(move_out_indices)
) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)> {
self.diags.buffered_move_errors.get(move_out_indices)
}
}
}

View File

@ -264,7 +264,7 @@ pub(super) fn dump_annotation<'tcx>(
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
opaque_type_values: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
errors: &mut crate::error::BorrowckErrors<'tcx>,
diags: &mut crate::diags::BorrowckDiags<'tcx>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@ -310,7 +310,7 @@ pub(super) fn dump_annotation<'tcx>(
err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}"));
}
errors.buffer_non_error_diag(err);
diags.buffer_non_error(err);
}
fn for_each_region_constraint<'tcx>(

View File

@ -408,7 +408,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &Locke
.filter(|_feature| {
target_info.cpu_supports(_feature)
/*
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma,
adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma,
avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq,
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves

View File

@ -102,7 +102,7 @@ pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_> {
fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> {
let diag: DiagnosticBuilder<'_, G> = self.0.into_diagnostic(dcx, level);
let (message, _) = diag.messages().first().expect("`LlvmError` with no message");
let (message, _) = diag.messages.first().expect("`LlvmError` with no message");
let message = dcx.eagerly_translate_to_string(message.clone(), diag.args());
DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config)

View File

@ -39,7 +39,6 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet};
use crate::errors::ErrorCreatingRemarkDir;
use std::any::Any;
use std::borrow::Cow;
use std::fs;
use std::io;
use std::marker::PhantomData;
@ -1812,12 +1811,12 @@ impl Translate for SharedEmitter {
impl Emitter for SharedEmitter {
fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) {
let args: FxHashMap<Cow<'_, str>, DiagnosticArgValue> =
let args: FxHashMap<DiagnosticArgName, DiagnosticArgValue> =
diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect();
drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
msgs: diag.messages.clone(),
args: args.clone(),
code: diag.code.clone(),
code: diag.code,
lvl: diag.level(),
})));
for child in &diag.children {

View File

@ -1,6 +1,8 @@
use std::mem;
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg};
use rustc_errors::{
DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg,
};
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::mir::AssertKind;
use rustc_middle::query::TyCtxtAt;
@ -32,10 +34,7 @@ impl MachineStopType for ConstEvalErrKind {
AssertFailure(x) => x.diagnostic_message(),
}
}
fn add_args(
self: Box<Self>,
adder: &mut dyn FnMut(std::borrow::Cow<'static, str>, DiagnosticArgValue),
) {
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) {
use ConstEvalErrKind::*;
match *self {
ConstAccessesStatic | ModifiedGlobal => {}

View File

@ -33,7 +33,10 @@ pub type DiagnosticArgName = Cow<'static, str>;
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DiagnosticArgValue {
Str(Cow<'static, str>),
Number(i128),
// This gets converted to a `FluentNumber`, which is an `f64`. An `i32`
// safely fits in an `f64`. Any integers bigger than that will be converted
// to strings in `into_diagnostic_arg` and stored using the `Str` variant.
Number(i32),
StrListSepByAnd(Vec<Cow<'static, str>>),
}
@ -113,7 +116,7 @@ pub struct Diagnostic {
/// With `-Ztrack_diagnostics` enabled,
/// we print where in rustc this error was emitted.
pub emitted_at: DiagnosticLocation,
pub(crate) emitted_at: DiagnosticLocation,
}
#[derive(Clone, Debug, Encodable, Decodable)]
@ -162,10 +165,10 @@ impl DiagnosticStyledString {
DiagnosticStyledString(vec![])
}
pub fn push_normal<S: Into<String>>(&mut self, t: S) {
self.0.push(StringPart::Normal(t.into()));
self.0.push(StringPart::normal(t));
}
pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
self.0.push(StringPart::Highlighted(t.into()));
self.0.push(StringPart::highlighted(t));
}
pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
if highlight {
@ -175,35 +178,34 @@ impl DiagnosticStyledString {
}
}
pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
DiagnosticStyledString(vec![StringPart::Normal(t.into())])
DiagnosticStyledString(vec![StringPart::normal(t)])
}
pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
DiagnosticStyledString(vec![StringPart::highlighted(t)])
}
pub fn content(&self) -> String {
self.0.iter().map(|x| x.content()).collect::<String>()
self.0.iter().map(|x| x.content.as_str()).collect::<String>()
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum StringPart {
Normal(String),
Highlighted(String),
pub struct StringPart {
content: String,
style: Style,
}
impl StringPart {
pub fn content(&self) -> &str {
match self {
&StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s,
}
pub fn normal<S: Into<String>>(content: S) -> StringPart {
StringPart { content: content.into(), style: Style::NoStyle }
}
pub fn highlighted<S: Into<String>>(content: S) -> StringPart {
StringPart { content: content.into(), style: Style::Highlight }
}
}
// Note: most of these methods are setters that return `&mut Self`. The small
// number of simple getter functions all have `get_` prefixes to distinguish
// them from the setters.
impl Diagnostic {
#[track_caller]
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
@ -389,19 +391,16 @@ impl Diagnostic {
} else {
(0, found_label.len() - expected_label.len())
};
let mut msg: Vec<_> =
vec![(format!("{}{} `", " ".repeat(expected_padding), expected_label), Style::NoStyle)];
msg.extend(expected.0.iter().map(|x| match *x {
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
}));
msg.push((format!("`{expected_extra}\n"), Style::NoStyle));
msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle));
msg.extend(found.0.iter().map(|x| match *x {
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
}));
msg.push((format!("`{found_extra}"), Style::NoStyle));
let mut msg = vec![StringPart::normal(format!(
"{}{} `",
" ".repeat(expected_padding),
expected_label
))];
msg.extend(expected.0.into_iter());
msg.push(StringPart::normal(format!("`{expected_extra}\n")));
msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label)));
msg.extend(found.0.into_iter());
msg.push(StringPart::normal(format!("`{found_extra}")));
// For now, just attach these as notes.
self.highlighted_note(msg);
@ -410,9 +409,9 @@ impl Diagnostic {
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
self.highlighted_note(vec![
(format!("`{name}` from trait: `"), Style::NoStyle),
(signature, Style::Highlight),
("`".to_string(), Style::NoStyle),
StringPart::normal(format!("`{name}` from trait: `")),
StringPart::highlighted(signature),
StringPart::normal("`"),
]);
self
}
@ -424,10 +423,7 @@ impl Diagnostic {
self
}
fn highlighted_note<M: Into<SubdiagnosticMessage>>(
&mut self,
msg: Vec<(M, Style)>,
) -> &mut Self {
fn highlighted_note(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Note, msg, MultiSpan::new());
self
}
@ -496,7 +492,7 @@ impl Diagnostic {
}
/// Add a help message attached to this diagnostic with a customizable highlighted message.
pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
pub fn highlighted_help(&mut self, msg: Vec<StringPart>) -> &mut Self {
self.sub_with_highlights(Level::Help, msg, MultiSpan::new());
self
}
@ -890,15 +886,6 @@ impl Diagnostic {
self
}
pub fn clear_code(&mut self) -> &mut Self {
self.code = None;
self
}
pub fn get_code(&self) -> Option<ErrCode> {
self.code
}
pub fn primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
self.messages[0] = (msg.into(), Style::NoStyle);
self
@ -913,7 +900,7 @@ impl Diagnostic {
pub fn arg(
&mut self,
name: impl Into<Cow<'static, str>>,
name: impl Into<DiagnosticArgName>,
arg: impl IntoDiagnosticArg,
) -> &mut Self {
self.args.insert(name.into(), arg.into_diagnostic_arg());
@ -924,10 +911,6 @@ impl Diagnostic {
self.args = args;
}
pub fn messages(&self) -> &[(DiagnosticMessage, Style)] {
&self.messages
}
/// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
/// passes the user's string along).
@ -958,15 +941,10 @@ impl Diagnostic {
/// Convenience function for internal use, clients should use one of the
/// public methods above.
fn sub_with_highlights<M: Into<SubdiagnosticMessage>>(
&mut self,
level: Level,
messages: Vec<(M, Style)>,
span: MultiSpan,
) {
fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
let messages = messages
.into_iter()
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1))
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
.collect();
let sub = SubDiagnostic { level, messages, span };
self.children.push(sub);

View File

@ -255,13 +255,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
/// Stashes diagnostic for possible later improvement in a different,
/// later stage of the compiler. The diagnostic can be accessed with
/// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
pub fn stash(self, span: Span, key: StashKey) {
self.dcx.stash_diagnostic(span, key, self.into_diagnostic());
}
/// Converts the builder to a `Diagnostic` for later emission.
pub fn into_diagnostic(mut self) -> Diagnostic {
self.take_diag()
pub fn stash(mut self, span: Span, key: StashKey) {
self.dcx.stash_diagnostic(span, key, self.take_diag());
}
/// Delay emission of this diagnostic as a bug.

View File

@ -63,12 +63,8 @@ macro_rules! into_diagnostic_arg_for_number {
$(
impl IntoDiagnosticArg for $ty {
fn into_diagnostic_arg(self) -> DiagnosticArgValue {
// HACK: `FluentNumber` the underline backing struct represent
// numbers using a f64 which can't represent all the i128 numbers
// So in order to be able to use fluent selectors and still
// have all the numbers representable we only convert numbers
// below a certain threshold.
if let Ok(n) = TryInto::<i128>::try_into(self) && n >= -100 && n <= 100 {
// Convert to a string if it won't fit into `Number`.
if let Ok(n) = TryInto::<i32>::try_into(self) {
DiagnosticArgValue::Number(n)
} else {
self.to_string().into_diagnostic_arg()

View File

@ -558,7 +558,7 @@ impl Emitter for HumanEmitter {
/// failures of rustc, as witnessed e.g. in issue #89358.
pub struct SilentEmitter {
pub fatal_dcx: DiagCtxt,
pub fatal_note: Option<String>,
pub fatal_note: String,
}
impl Translate for SilentEmitter {
@ -576,13 +576,11 @@ impl Emitter for SilentEmitter {
None
}
fn emit_diagnostic(&mut self, d: &Diagnostic) {
if d.level == Level::Fatal {
let mut d = d.clone();
if let Some(ref note) = self.fatal_note {
d.note(note.clone());
}
self.fatal_dcx.emit_diagnostic(d);
fn emit_diagnostic(&mut self, diag: &Diagnostic) {
if diag.level == Level::Fatal {
let mut diag = diag.clone();
diag.note(self.fatal_note.clone());
self.fatal_dcx.emit_diagnostic(diag);
}
}
}

View File

@ -34,7 +34,7 @@ extern crate self as rustc_errors;
pub use codes::*;
pub use diagnostic::{
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName,
DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, StringPart, SubDiagnostic,
};
pub use diagnostic_builder::{
BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic,
@ -102,7 +102,6 @@ pub type PResult<'a, T> = Result<T, PErr<'a>>;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.)
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16);
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@ -1039,10 +1038,6 @@ impl DiagCtxt {
}
}
pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics)
}
pub fn abort_if_errors(&self) {
let mut inner = self.inner.borrow_mut();
inner.emit_stashed_diagnostics();
@ -1150,8 +1145,12 @@ impl DiagCtxt {
self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
}
pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) {
self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
pub fn emit_future_breakage_report(&self) {
let mut inner = self.inner.borrow_mut();
let diags = std::mem::take(&mut inner.future_breakage_diagnostics);
if !diags.is_empty() {
inner.emitter.emit_future_breakage_report(diags);
}
}
pub fn emit_unused_externs(
@ -1224,9 +1223,8 @@ impl DiagCtxtInner {
/// Emit all stashed diagnostics.
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
let has_errors = self.has_errors();
let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
let mut reported = None;
for diag in diags {
for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
// Decrement the count tracking the stash; emitting will increment it.
if diag.is_error() {
if diag.is_lint.is_some() {
@ -1254,7 +1252,7 @@ impl DiagCtxtInner {
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
// a stable one by the `LintLevelsBuilder`.
if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() {
self.unstable_expect_diagnostics.push(diagnostic.clone());
self.unstable_expect_diagnostics.push(diagnostic);
return None;
}
@ -1269,16 +1267,14 @@ impl DiagCtxtInner {
DelayedBug(DelayedBugKind::Normal) => {
let backtrace = std::backtrace::Backtrace::capture();
self.span_delayed_bugs
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
#[allow(deprecated)]
return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
}
DelayedBug(DelayedBugKind::GoodPath) => {
let backtrace = std::backtrace::Backtrace::capture();
self.good_path_delayed_bugs
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
return None;
}
_ => {}
@ -1424,7 +1420,7 @@ impl DiagCtxtInner {
&mut out,
"delayed span bug: {}\n{}\n",
bug.inner
.messages()
.messages
.iter()
.filter_map(|(msg, _)| msg.as_str())
.collect::<String>(),

View File

@ -197,7 +197,7 @@ pub struct StyledString {
pub style: Style,
}
#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum Style {
MainHeaderMsg,
HeaderMsg,

View File

@ -894,34 +894,23 @@ impl<'tcx> OwnerInfo<'tcx> {
}
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum MaybeOwner<T> {
Owner(T),
pub enum MaybeOwner<'tcx> {
Owner(&'tcx OwnerInfo<'tcx>),
NonOwner(HirId),
/// Used as a placeholder for unused LocalDefId.
Phantom,
}
impl<T> MaybeOwner<T> {
pub fn as_owner(self) -> Option<T> {
impl<'tcx> MaybeOwner<'tcx> {
pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> {
match self {
MaybeOwner::Owner(i) => Some(i),
MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None,
}
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> MaybeOwner<U> {
match self {
MaybeOwner::Owner(i) => MaybeOwner::Owner(f(i)),
MaybeOwner::NonOwner(hir_id) => MaybeOwner::NonOwner(hir_id),
MaybeOwner::Phantom => MaybeOwner::Phantom,
}
}
pub fn unwrap(self) -> T {
match self {
MaybeOwner::Owner(i) => i,
MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => panic!("Not a HIR owner"),
}
pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> {
self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner"))
}
}
@ -933,7 +922,7 @@ impl<T> MaybeOwner<T> {
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#[derive(Debug)]
pub struct Crate<'hir> {
pub owners: IndexVec<LocalDefId, MaybeOwner<&'hir OwnerInfo<'hir>>>,
pub owners: IndexVec<LocalDefId, MaybeOwner<'hir>>,
// Only present when incr. comp. is enabled.
pub opt_hir_hash: Option<Fingerprint>,
}

View File

@ -247,7 +247,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.span_suggestion_verbose(
assoc_name.span,
fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg,
suggested_name.to_string(),
suggested_name,
Applicability::MaybeIncorrect,
);
}

View File

@ -590,7 +590,6 @@ fn infer_placeholder_type<'a>(
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
// We are typeck and have the real type, so remove that and suggest the actual type.
// FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
if let Ok(suggestions) = &mut err.suggestions {
suggestions.clear();
}

View File

@ -1000,7 +1000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestion_verbose(
lhs.span.shrink_to_hi(),
"you might have meant to write a semicolon here",
";".to_string(),
";",
Applicability::MachineApplicable,
);
return true;

View File

@ -1116,9 +1116,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
item_name.span,
format!(
"you might have meant to use `{}`",
inherent_method.name.as_str()
inherent_method.name
),
inherent_method.name.as_str(),
inherent_method.name,
Applicability::MaybeIncorrect,
);
break 'outer;
@ -2019,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diag.span_suggestion_verbose(
sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(),
"you may have meant to call an instance method",
".".to_string(),
".",
Applicability::MaybeIncorrect,
);
}

View File

@ -576,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if (lhs, rhs).references_error() {
err.downgrade_to_delayed_bug();
}
if self.tcx.sess.teach(err.get_code().unwrap()) {
if self.tcx.sess.teach(err.code.unwrap()) {
err.note(
"In a match expression, only numbers and characters can be matched \
against a range. This is because the compiler checks that the range \
@ -847,7 +847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
type_str
);
err.span_label(span, format!("type `{type_str}` cannot be dereferenced"));
if self.tcx.sess.teach(err.get_code().unwrap()) {
if self.tcx.sess.teach(err.code.unwrap()) {
err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ);
}
return Err(err.emit());
@ -1669,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
if tcx.sess.teach(err.get_code().unwrap()) {
if tcx.sess.teach(err.code.unwrap()) {
err.note(
"This error indicates that a struct pattern attempted to \
extract a nonexistent field from a struct. Struct fields \

View File

@ -195,7 +195,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
}
diag.help("type parameters must be constrained to match other types");
if tcx.sess.teach(diag.get_code().unwrap()) {
if tcx.sess.teach(diag.code.unwrap()) {
diag.help(
"given a type parameter `T` and a method `foo`:
```
@ -678,7 +678,7 @@ impl<T> Trait<T> for X {
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
);
}
if tcx.sess.teach(diag.get_code().unwrap()) {
if tcx.sess.teach(diag.code.unwrap()) {
diag.help(
"given an associated type `T` and a method `foo`:
```

View File

@ -45,20 +45,19 @@ pub struct Compiler {
pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
cfgs.into_iter()
.map(|s| {
let sess = ParseSess::with_silent_emitter(Some(format!(
let sess = ParseSess::with_silent_emitter(format!(
"this error occurred on the command line: `--cfg={s}`"
)));
));
let filename = FileName::cfg_spec_source_code(&s);
macro_rules! error {
($reason: expr) => {
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
dcx.struct_fatal(format!(
dcx.fatal(format!(
concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
s
))
.emit();
));
};
}
@ -108,20 +107,19 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
for s in specs {
let sess = ParseSess::with_silent_emitter(Some(format!(
let sess = ParseSess::with_silent_emitter(format!(
"this error occurred on the command line: `--check-cfg={s}`"
)));
));
let filename = FileName::cfg_spec_source_code(&s);
macro_rules! error {
($reason:expr) => {
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
dcx.struct_fatal(format!(
dcx.fatal(format!(
concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
s
))
.emit()
};
}

View File

@ -1,7 +1,6 @@
use std::borrow::Cow;
use std::fmt;
use rustc_errors::{codes::*, DiagnosticArgValue, DiagnosticMessage};
use rustc_errors::{codes::*, DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage};
use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
@ -95,14 +94,14 @@ pub(super) struct ConstNotUsedTraitAlias {
pub struct CustomSubdiagnostic<'a> {
pub msg: fn() -> DiagnosticMessage,
pub add_args: Box<dyn FnOnce(&mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue)) + 'a>,
pub add_args: Box<dyn FnOnce(&mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) + 'a>,
}
impl<'a> CustomSubdiagnostic<'a> {
pub fn label(x: fn() -> DiagnosticMessage) -> Self {
Self::label_and_then(x, |_| {})
}
pub fn label_and_then<F: FnOnce(&mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue)) + 'a>(
pub fn label_and_then<F: FnOnce(&mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) + 'a>(
msg: fn() -> DiagnosticMessage,
f: F,
) -> Self {

View File

@ -127,12 +127,11 @@ pub fn provide(providers: &mut Providers) {
providers.hir_crate_items = map::hir_crate_items;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.opt_local_def_id_to_hir_id = |tcx, id| {
let owner = tcx.hir_crate(()).owners[id].map(|_| ());
Some(match owner {
MaybeOwner::Owner(_) => HirId::make_owner(id),
MaybeOwner::Phantom => bug!("No HirId for {:?}", id),
providers.opt_local_def_id_to_hir_id = |tcx, def_id| {
Some(match tcx.hir_crate(()).owners[def_id] {
MaybeOwner::Owner(_) => HirId::make_owner(def_id),
MaybeOwner::NonOwner(hir_id) => hir_id,
MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id),
})
};
providers.opt_hir_owner_nodes =

View File

@ -5,7 +5,9 @@ use crate::mir::{ConstAlloc, ConstValue};
use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
use rustc_data_structures::sync::Lock;
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_errors::{
DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg,
};
use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace;
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
@ -485,7 +487,7 @@ pub trait MachineStopType: Any + fmt::Debug + Send {
fn diagnostic_message(&self) -> DiagnosticMessage;
/// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to
/// fluent for formatting the translated diagnostic message.
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue));
fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue));
}
impl dyn MachineStopType {

View File

@ -14,7 +14,9 @@ use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex};
use crate::ty::{GenericArg, GenericArgsRef};
use rustc_data_structures::captures::Captures;
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_errors::{
DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg,
};
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind};

View File

@ -292,7 +292,7 @@ impl<O> AssertKind<O> {
}
}
pub fn add_args(self, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue))
pub fn add_args(self, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue))
where
O: fmt::Debug,
{

View File

@ -185,8 +185,8 @@ impl EraseType for Option<ty::EarlyBinder<Ty<'_>>> {
type Result = [u8; size_of::<Option<ty::EarlyBinder<Ty<'static>>>>()];
}
impl<T> EraseType for rustc_hir::MaybeOwner<&'_ T> {
type Result = [u8; size_of::<rustc_hir::MaybeOwner<&'static ()>>()];
impl EraseType for rustc_hir::MaybeOwner<'_> {
type Result = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
}
impl<T: EraseType> EraseType for ty::EarlyBinder<T> {

View File

@ -34,7 +34,7 @@ pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
fn add_args(
self: Box<Self>,
_: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue),
_: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue),
) {}
}
throw_machine_stop!(Zst)

View File

@ -39,7 +39,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
// uses a HOF to parse anything, and <source> includes file and
// `source_str`.
/// A variant of 'panictry!' that works on a `Vec<Diagnostic>` instead of a single
/// A variant of 'panictry!' that works on a `Vec<DiagnosticBuilder>` instead of a single
/// `DiagnosticBuilder`.
macro_rules! panictry_buffer {
($e:expr) => {{

View File

@ -3288,7 +3288,7 @@ impl<'a> Parser<'a> {
} else {
Applicability::MaybeIncorrect
};
err.span_suggestion_verbose(sugg_sp, msg, "=> ".to_string(), applicability);
err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
}
}
err

View File

@ -148,7 +148,7 @@ impl<'a> Parser<'a> {
.with_span_suggestion_verbose(
mistyped_const_ident.span,
"use the `const` keyword",
kw::Const.as_str(),
kw::Const,
Applicability::MachineApplicable,
)
.emit();

View File

@ -1453,7 +1453,7 @@ impl<'a> Parser<'a> {
err.span_suggestion_verbose(
prev_span,
"perhaps you meant to use `struct` here",
"struct".to_string(),
"struct",
Applicability::MaybeIncorrect,
);
}

View File

@ -464,7 +464,11 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
self.lookup_and_handle_method(expr.hir_id);
}
hir::ExprKind::Field(ref lhs, ..) => {
self.handle_field_access(lhs, expr.hir_id);
if self.typeck_results().opt_field_index(expr.hir_id).is_some() {
self.handle_field_access(lhs, expr.hir_id);
} else {
self.tcx.dcx().span_delayed_bug(expr.span, "couldn't resolve index for field");
}
}
hir::ExprKind::Struct(qpath, fields, _) => {
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);

View File

@ -289,6 +289,9 @@ resolve_underscore_lifetime_name_cannot_be_used_here =
`'_` cannot be used here
.note = `'_` is a reserved lifetime name
resolve_unexpected_res_change_ty_to_const_param_sugg =
you might have meant to write a const parameter here
resolve_unreachable_label =
use of unreachable label `{$name}`
.label = unreachable label `{$name}`

View File

@ -1,4 +1,4 @@
use rustc_errors::codes::*;
use rustc_errors::{codes::*, Applicability};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{
symbol::{Ident, Symbol},
@ -787,3 +787,16 @@ pub(crate) struct IsNotDirectlyImportable {
pub(crate) span: Span,
pub(crate) target: Ident,
}
#[derive(Subdiagnostic)]
#[suggestion(
resolve_unexpected_res_change_ty_to_const_param_sugg,
code = "const ",
style = "verbose"
)]
pub(crate) struct UnexpectedResChangeTyToConstParamSugg {
#[primary_span]
pub span: Span,
#[applicability]
pub applicability: Applicability,
}

View File

@ -594,9 +594,9 @@ struct DiagnosticMetadata<'ast> {
/// The current trait (used to suggest).
current_item: Option<&'ast Item>,
/// When processing generics and encountering a type not found, suggest introducing a type
/// param.
currently_processing_generics: bool,
/// When processing generic arguments and encountering an unresolved ident not found,
/// suggest introducing a type or const param depending on the context.
currently_processing_generic_args: bool,
/// The current enclosing (non-closure) function (used for better errors).
current_function: Option<(FnKind<'ast>, Span)>,
@ -1069,7 +1069,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
debug!("visit_generic_arg({:?})", arg);
let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true);
let prev = replace(&mut self.diagnostic_metadata.currently_processing_generic_args, true);
match arg {
GenericArg::Type(ref ty) => {
// We parse const arguments as path types as we cannot distinguish them during
@ -1100,7 +1100,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
},
);
self.diagnostic_metadata.currently_processing_generics = prev;
self.diagnostic_metadata.currently_processing_generic_args = prev;
return;
}
}
@ -1113,7 +1113,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No))
}
}
self.diagnostic_metadata.currently_processing_generics = prev;
self.diagnostic_metadata.currently_processing_generic_args = prev;
}
fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {

View File

@ -444,6 +444,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
self.suggest_bare_struct_literal(&mut err);
self.suggest_changing_type_to_const_param(&mut err, res, source, span);
if self.suggest_pattern_match_with_let(&mut err, source, span) {
// Fallback label.
@ -452,7 +453,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
self.suggest_self_or_self_ref(&mut err, path, span);
self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error);
if self.suggest_self_ty(&mut err, source, path, span)
|| self.suggest_self_value(&mut err, source, path, span)
{
@ -491,7 +492,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
(err, candidates)
}
fn detect_assoct_type_constraint_meant_as_path(
fn detect_assoc_type_constraint_meant_as_path(
&self,
err: &mut Diagnostic,
base_error: &BaseError,
@ -699,7 +700,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_suggestion_verbose(
span.shrink_to_lo(),
msg,
"self.".to_string(),
"self.",
Applicability::MachineApplicable,
);
}
@ -710,7 +711,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_suggestion_verbose(
span.shrink_to_lo(),
format!("you might have meant to {}", candidate.action()),
"Self::".to_string(),
"Self::",
Applicability::MachineApplicable,
);
}
@ -799,7 +800,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
false,
) = (source, res, is_macro)
{
if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
if let Some(bounds @ [first_bound, .., last_bound]) =
self.diagnostic_metadata.current_trait_object
{
fallback = true;
let spans: Vec<Span> = bounds
.iter()
@ -807,9 +810,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.filter(|&sp| sp != base_error.span)
.collect();
let start_span = bounds[0].span();
let start_span = first_bound.span();
// `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
let end_span = bounds.last().unwrap().span();
let end_span = last_bound.span();
// `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
let last_bound_span = spans.last().cloned().unwrap();
let mut multi_span: MultiSpan = spans.clone().into();
@ -1136,6 +1139,55 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
}
fn suggest_changing_type_to_const_param(
&mut self,
err: &mut Diagnostic,
res: Option<Res>,
source: PathSource<'_>,
span: Span,
) {
let PathSource::Trait(_) = source else { return };
// We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway.
let applicability = match res {
Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => {
Applicability::MachineApplicable
}
// FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic
// const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the
// benefits of including them here outweighs the small number of false positives.
Some(Res::Def(DefKind::Struct | DefKind::Enum, _))
if self.r.tcx.features().adt_const_params =>
{
Applicability::MaybeIncorrect
}
_ => return,
};
let Some(item) = self.diagnostic_metadata.current_item else { return };
let Some(generics) = item.kind.generics() else { return };
let param = generics.params.iter().find_map(|param| {
// Only consider type params with exactly one trait bound.
if let [bound] = &*param.bounds
&& let ast::GenericBound::Trait(tref, ast::TraitBoundModifiers::NONE) = bound
&& tref.span == span
&& param.ident.span.eq_ctxt(span)
{
Some(param.ident.span)
} else {
None
}
});
if let Some(param) = param {
err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg {
span: param.shrink_to_lo(),
applicability,
});
}
}
fn suggest_pattern_match_with_let(
&mut self,
err: &mut Diagnostic,
@ -2419,10 +2471,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let mut iter = ident.chars().map(|c| c.is_uppercase());
let single_uppercase_char =
matches!(iter.next(), Some(true)) && matches!(iter.next(), None);
if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char {
if !self.diagnostic_metadata.currently_processing_generic_args && !single_uppercase_char {
return None;
}
match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) {
match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generic_args) {
(Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
// Ignore `fn main()` as we don't want to suggest `fn main<T>()`
}

View File

@ -258,7 +258,7 @@ impl ParseSess {
}
}
pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
pub fn with_silent_emitter(fatal_note: String) -> Self {
let fallback_bundle = fallback_fluent_bundle(Vec::new(), false);
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let fatal_dcx = DiagCtxt::with_tty_emitter(None, fallback_bundle).disable_warnings();

View File

@ -288,19 +288,9 @@ impl Session {
pub fn finish_diagnostics(&self, registry: &Registry) {
self.check_miri_unleashed_features();
self.dcx().print_error_count(registry);
self.emit_future_breakage();
}
fn emit_future_breakage(&self) {
if !self.opts.json_future_incompat {
return;
if self.opts.json_future_incompat {
self.dcx().emit_future_breakage_report();
}
let diags = self.dcx().take_future_breakage_diagnostics();
if diags.is_empty() {
return;
}
self.dcx().emit_future_breakage_report(diags);
}
/// Returns true if the crate is a testing one.

View File

@ -201,6 +201,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[
("avx512dq", Unstable(sym::avx512_target_feature)),
("avx512er", Unstable(sym::avx512_target_feature)),
("avx512f", Unstable(sym::avx512_target_feature)),
("avx512fp16", Unstable(sym::avx512_target_feature)),
("avx512ifma", Unstable(sym::avx512_target_feature)),
("avx512pf", Unstable(sym::avx512_target_feature)),
("avx512vbmi", Unstable(sym::avx512_target_feature)),

View File

@ -1288,7 +1288,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_suggestion_verbose(
obligation.cause.span.shrink_to_hi(),
"consider using clone here",
".clone()".to_string(),
".clone()",
Applicability::MaybeIncorrect,
);
return true;
@ -2717,7 +2717,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let (trait_name, trait_verb) =
if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
err.clear_code();
err.code = None;
err.primary_message(format!(
"{future_or_coroutine} cannot be {trait_verb} between threads safely"
));
@ -3245,7 +3245,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_suggestion_verbose(
span,
"you can use `impl Trait` as the argument type",
"impl ".to_string(),
"impl ",
Applicability::MaybeIncorrect,
);
let sugg = if !needs_parens {
@ -5203,7 +5203,7 @@ fn point_at_assoc_type_restriction(
err.span_suggestion_verbose(
path.span,
"replace the associated type with the type specified in this `impl`",
tcx.type_of(new.def_id).skip_binder().to_string(),
tcx.type_of(new.def_id).skip_binder(),
Applicability::MachineApplicable,
);
}

View File

@ -20,7 +20,7 @@ use crate::traits::{
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{
codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder,
ErrorGuaranteed, MultiSpan, StashKey, Style,
ErrorGuaranteed, MultiSpan, StashKey, StringPart,
};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, Res};
@ -2059,11 +2059,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()),
});
err.highlighted_help(vec![
(format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
("is".to_string(), Style::Highlight),
(" implemented for `".to_string(), Style::NoStyle),
(cand.self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
StringPart::highlighted("is"),
StringPart::normal(" implemented for `"),
StringPart::highlighted(cand.self_ty().to_string()),
StringPart::normal("`"),
]);
if let [TypeError::Sorts(exp_found)] = &terrs[..] {
@ -2095,12 +2095,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => (" implemented for `", ""),
};
err.highlighted_help(vec![
(format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle),
("is".to_string(), Style::Highlight),
(desc.to_string(), Style::NoStyle),
(cand.self_ty().to_string(), Style::Highlight),
("`".to_string(), Style::NoStyle),
(mention_castable.to_string(), Style::NoStyle),
StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())),
StringPart::highlighted("is"),
StringPart::normal(desc),
StringPart::highlighted(cand.self_ty().to_string()),
StringPart::normal("`"),
StringPart::normal(mention_castable),
]);
return true;
}

View File

@ -200,7 +200,6 @@
//
// Language features:
// tidy-alphabetical-start
#![cfg_attr(not(bootstrap), feature(is_val_statically_known))]
#![feature(abi_unadjusted)]
#![feature(adt_const_params)]
#![feature(allow_internal_unsafe)]

View File

@ -1374,59 +1374,26 @@ macro_rules! int_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.unsigned_abs().is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return Some(1);
}
if self == -1 { // Avoid divide by zero
return Some(if exp & 1 != 0 { -1 } else { 1 });
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
if exp > Self::BITS / power_used { return None; } // Division of constants is free
// SAFETY: exp <= Self::BITS / power_used
let res = unsafe { intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
)};
// LLVM doesn't always optimize out the checks
// at the ir level.
let sign = self.is_negative() && exp & 1 != 0;
if !sign && res == Self::MIN {
None
} else if sign {
Some(res.wrapping_neg())
} else {
Some(res)
}
} else {
if exp == 0 {
return Some(1);
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = try_opt!(acc.checked_mul(base));
}
exp /= 2;
base = try_opt!(base.checked_mul(base));
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.checked_mul(base)
if exp == 0 {
return Some(1);
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = try_opt!(acc.checked_mul(base));
}
exp /= 2;
base = try_opt!(base.checked_mul(base));
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.checked_mul(base)
}
/// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@ -2091,58 +2058,27 @@ macro_rules! int_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.unsigned_abs().is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return 1;
}
if self == -1 { // Avoid divide by zero
return if exp & 1 != 0 { -1 } else { 1 };
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
if exp > Self::BITS / power_used { return 0; } // Division of constants is free
// SAFETY: exp <= Self::BITS / power_used
let res = unsafe { intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
)};
// LLVM doesn't always optimize out the checks
// at the ir level.
let sign = self.is_negative() && exp & 1 != 0;
if sign {
res.wrapping_neg()
} else {
res
}
} else {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.wrapping_mul(base);
}
exp /= 2;
base = base.wrapping_mul(base);
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.wrapping_mul(base)
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.wrapping_mul(base);
}
exp /= 2;
base = base.wrapping_mul(base);
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.wrapping_mul(base)
}
/// Calculates `self` + `rhs`
@ -2625,68 +2561,36 @@ macro_rules! int_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.unsigned_abs().is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return (1, false);
}
if self == -1 { // Avoid divide by zero
return (if exp & 1 != 0 { -1 } else { 1 }, false);
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
if exp > Self::BITS / power_used { return (0, true); } // Division of constants is free
if exp == 0 {
return (1,false);
}
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
// Scratch space for storing results of overflowing_mul.
let mut r;
// SAFETY: exp <= Self::BITS / power_used
let res = unsafe { intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
)};
// LLVM doesn't always optimize out the checks
// at the ir level.
let sign = self.is_negative() && exp & 1 != 0;
let overflow = res == Self::MIN;
if sign {
(res.wrapping_neg(), overflow)
} else {
(res, overflow)
}
} else {
if exp == 0 {
return (1,false);
}
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
// Scratch space for storing results of overflowing_mul.
let mut r;
while exp > 1 {
if (exp & 1) == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
exp /= 2;
r = base.overflowing_mul(base);
base = r.0;
while exp > 1 {
if (exp & 1) == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
r = acc.overflowing_mul(base);
r.1 |= overflown;
r
exp /= 2;
r = base.overflowing_mul(base);
base = r.0;
overflown |= r.1;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
r = acc.overflowing_mul(base);
r.1 |= overflown;
r
}
/// Raises self to the power of `exp`, using exponentiation by squaring.
@ -2704,68 +2608,28 @@ macro_rules! int_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
#[rustc_inherit_overflow_checks]
#[track_caller] // Hides the hackish overflow check for powers of two.
pub const fn pow(self, mut exp: u32) -> Self {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.unsigned_abs().is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return 1;
}
if self == -1 { // Avoid divide by zero
return if exp & 1 != 0 { -1 } else { 1 };
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
if exp > Self::BITS / power_used { // Division of constants is free
#[allow(arithmetic_overflow)]
return Self::MAX * Self::MAX * 0;
}
// SAFETY: exp <= Self::BITS / power_used
let res = unsafe { intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
)};
// LLVM doesn't always optimize out the checks
// at the ir level.
let sign = self.is_negative() && exp & 1 != 0;
#[allow(arithmetic_overflow)]
if !sign && res == Self::MIN {
// So it panics.
_ = Self::MAX * Self::MAX;
}
if sign {
res.wrapping_neg()
} else {
res
}
} else {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc * base;
}
exp /= 2;
base = base * base;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc * base
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc * base;
}
exp /= 2;
base = base * base;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc * base
}
/// Returns the square root of the number, rounded down.

View File

@ -1364,49 +1364,28 @@ macro_rules! uint_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return Some(1);
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
if exp > Self::BITS / power_used { return None; } // Division of constants is free
// SAFETY: exp <= Self::BITS / power_used
unsafe { Some(intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
)) }
// LLVM doesn't always optimize out the checks
// at the ir level.
} else {
if exp == 0 {
return Some(1);
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = try_opt!(acc.checked_mul(base));
}
exp /= 2;
base = try_opt!(base.checked_mul(base));
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.checked_mul(base)
if exp == 0 {
return Some(1);
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = try_opt!(acc.checked_mul(base));
}
exp /= 2;
base = try_opt!(base.checked_mul(base));
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.checked_mul(base)
}
/// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@ -1908,48 +1887,27 @@ macro_rules! uint_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return 1;
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
if exp > Self::BITS / power_used { return 0; } // Division of constants is free
// SAFETY: exp <= Self::BITS / power_used
unsafe { intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
)}
// LLVM doesn't always optimize out the checks
// at the ir level.
} else {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.wrapping_mul(base);
}
exp /= 2;
base = base.wrapping_mul(base);
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.wrapping_mul(base)
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc: Self = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc.wrapping_mul(base);
}
exp /= 2;
base = base.wrapping_mul(base);
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc.wrapping_mul(base)
}
/// Calculates `self` + `rhs`
@ -2383,58 +2341,37 @@ macro_rules! uint_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return (1, false);
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
if exp > Self::BITS / power_used { return (0, true); } // Division of constants is free
if exp == 0{
return (1,false);
}
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
// Scratch space for storing results of overflowing_mul.
let mut r;
// SAFETY: exp <= Self::BITS / power_used
unsafe { (intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
), false) }
// LLVM doesn't always optimize out the checks
// at the ir level.
} else {
if exp == 0{
return (1,false);
}
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
// Scratch space for storing results of overflowing_mul.
let mut r;
while exp > 1 {
if (exp & 1) == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
exp /= 2;
r = base.overflowing_mul(base);
base = r.0;
while exp > 1 {
if (exp & 1) == 1 {
r = acc.overflowing_mul(base);
acc = r.0;
overflown |= r.1;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
r = acc.overflowing_mul(base);
r.1 |= overflown;
r
exp /= 2;
r = base.overflowing_mul(base);
base = r.0;
overflown |= r.1;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
r = acc.overflowing_mul(base);
r.1 |= overflown;
r
}
/// Raises self to the power of `exp`, using exponentiation by squaring.
@ -2450,64 +2387,28 @@ macro_rules! uint_impl {
#[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
#[inline]
#[rustc_inherit_overflow_checks]
#[track_caller] // Hides the hackish overflow check for powers of two.
pub const fn pow(self, mut exp: u32) -> Self {
// LLVM now knows that `self` is a constant value, but not a
// constant in Rust. This allows us to compute the power used at
// compile-time.
//
// This will likely add a branch in debug builds, but this should
// be ok.
//
// This is a massive performance boost in release builds as you can
// get the power of a power of two and the exponent through a `shl`
// instruction, but we must add a couple more checks for parity with
// our own `pow`.
// SAFETY: This path has the same behavior as the other.
if unsafe { intrinsics::is_val_statically_known(self) }
&& self.is_power_of_two()
{
if self == 1 { // Avoid divide by zero
return 1;
}
// SAFETY: We just checked this is a power of two. and above zero.
let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
if exp > Self::BITS / power_used { // Division of constants is free
#[allow(arithmetic_overflow)]
return Self::MAX * Self::MAX * 0;
}
// SAFETY: exp <= Self::BITS / power_used
unsafe { intrinsics::unchecked_shl(
1 as Self,
intrinsics::unchecked_mul(power_used, exp) as Self
)}
// LLVM doesn't always optimize out the checks
// at the ir level.
} else {
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc * base;
}
exp /= 2;
base = base * base;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc * base
if exp == 0 {
return 1;
}
let mut base = self;
let mut acc = 1;
while exp > 1 {
if (exp & 1) == 1 {
acc = acc * base;
}
exp /= 2;
base = base * base;
}
// since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
acc * base
}
/// Returns the square root of the number, rounded down.

View File

@ -1,55 +0,0 @@
// compile-flags: --crate-type=lib -Zmerge-functions=disabled -O -C overflow-checks=false
// CHECK-LABEL: @a(
#[no_mangle]
pub fn a(exp: u32) -> u64 {
// CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64
// CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64
// CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}}
// CHECK: ret i64 %{{[^ ]+}}
2u64.pow(exp)
}
// CHECK-LABEL: @b(
#[no_mangle]
pub fn b(exp: u32) -> i64 {
// CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64
// CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64
// CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}}
// CHECK: ret i64 %{{[^ ]+}}
2i64.pow(exp)
}
// CHECK-LABEL: @c(
#[no_mangle]
pub fn c(exp: u32) -> u32 {
// CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 16
// CHECK: %{{[^ ]+}} = shl nuw nsw i32 %exp, 1
// CHECK: %{{[^ ]+}} = shl nuw i32 1, %{{[^ ]+}}
// CHECK: %{{[^ ]+}} = select i1 %{{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
// CHECK: ret i32 %{{[^ ]+}}
4u32.pow(exp)
}
// CHECK-LABEL: @d(
#[no_mangle]
pub fn d(exp: u32) -> u32 {
// CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6
// CHECK: %{{[^ ]+}} = mul nuw nsw i32 %exp, 5
// CHECK: %{{[^ ]+}} = shl nuw nsw i32 1, %{{[^ ]+}}
// CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
// CHECK: ret i32 %{{[^ ]+}}
32u32.pow(exp)
}
// CHECK-LABEL: @e(
#[no_mangle]
pub fn e(exp: u32) -> i32 {
// CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6
// CHECK: %{{[^ ]+}} = mul nuw {{(nsw )?}}i32 %exp, 5
// CHECK: %{{[^ ]+}} = shl nuw {{(nsw )?}}i32 1, %{{[^ ]+}}
// CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
// CHECK: ret i32 %{{[^ ]+}}
32i32.pow(exp)
}
// note: d and e are expected to yield the same IR

View File

@ -1,81 +1,81 @@
Function name: bad_counter_ids::eq_bad
Raw bytes (14): 0x[01, 01, 00, 02, 01, 23, 01, 02, 1f, 00, 03, 01, 00, 02]
Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 1f, 00, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 35, 1) to (start + 2, 31)
- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 31)
- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
Function name: bad_counter_ids::eq_bad_message
Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 28, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 29, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Zero
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 40, 1) to (start + 2, 15)
- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15)
- Code(Expression(0, Sub)) at (prev + 2, 32) to (start + 0, 43)
= (c0 - Zero)
- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
Function name: bad_counter_ids::eq_good
Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 01, 02, 1f, 05, 03, 01, 00, 02]
Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 1f, 05, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 31)
- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 31)
- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
Function name: bad_counter_ids::eq_good_message
Raw bytes (19): 0x[01, 01, 00, 03, 01, 14, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02]
Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 20, 1) to (start + 2, 15)
- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15)
- Code(Zero) at (prev + 2, 32) to (start + 0, 43)
- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
Function name: bad_counter_ids::ne_bad
Raw bytes (14): 0x[01, 01, 00, 02, 01, 2d, 01, 02, 1f, 00, 03, 01, 00, 02]
Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 1f, 00, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 45, 1) to (start + 2, 31)
- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 31)
- Code(Zero) at (prev + 3, 1) to (start + 0, 2)
Function name: bad_counter_ids::ne_bad_message
Raw bytes (19): 0x[01, 01, 00, 03, 01, 32, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 50, 1) to (start + 2, 15)
- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15)
- Code(Counter(1)) at (prev + 2, 32) to (start + 0, 43)
- Code(Zero) at (prev + 1, 1) to (start + 0, 2)
Function name: bad_counter_ids::ne_good
Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 19, 01, 02, 1f, 02, 03, 01, 00, 02]
Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 1a, 01, 02, 1f, 02, 03, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Zero
Number of file 0 mappings: 2
- Code(Counter(0)) at (prev + 25, 1) to (start + 2, 31)
- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 31)
- Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2)
= (c0 - Zero)
Function name: bad_counter_ids::ne_good_message
Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1e, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02]
Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 1
- expression 0 operands: lhs = Counter(0), rhs = Zero
Number of file 0 mappings: 3
- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 15)
- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15)
- Code(Zero) at (prev + 2, 32) to (start + 0, 43)
- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2)
= (c0 - Zero)

View File

@ -1,5 +1,6 @@
LL| |#![feature(coverage_attribute)]
LL| |// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3
LL| |// edition: 2021
LL| |// compile-flags: -Copt-level=0 -Zmir-opt-level=3
LL| |
LL| |// Regression test for <https://github.com/rust-lang/rust/issues/117012>.
LL| |//

View File

@ -1,5 +1,6 @@
#![feature(coverage_attribute)]
// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3
// edition: 2021
// compile-flags: -Copt-level=0 -Zmir-opt-level=3
// Regression test for <https://github.com/rust-lang/rust/issues/117012>.
//

View File

@ -1,5 +1,5 @@
LL| |// compile-flags: --edition=2018
LL| |#![feature(coverage_attribute)]
LL| |// edition: 2018
LL| |
LL| |macro_rules! bail {
LL| | ($msg:literal $(,)?) => {

View File

@ -1,5 +1,5 @@
// compile-flags: --edition=2018
#![feature(coverage_attribute)]
// edition: 2018
macro_rules! bail {
($msg:literal $(,)?) => {

View File

@ -1,5 +1,5 @@
LL| |#![feature(coverage_attribute)]
LL| |// compile-flags: --edition=2021
LL| |// edition: 2021
LL| |
LL| |// Regression test for inconsistent handling of function signature spans that
LL| |// are followed by code using the `?` operator.

View File

@ -1,5 +1,5 @@
#![feature(coverage_attribute)]
// compile-flags: --edition=2021
// edition: 2021
// Regression test for inconsistent handling of function signature spans that
// are followed by code using the `?` operator.

View File

@ -1,24 +1,24 @@
Function name: issue_93054::foo2 (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 00, 1d]
Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1d]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 22, 1) to (start + 0, 29)
- Code(Zero) at (prev + 21, 1) to (start + 0, 29)
Function name: issue_93054::main
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 00, 0d]
Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 0d]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 13)
- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 13)
Function name: issue_93054::make (unused)
Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 01, 02, 02]
Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02]
Number of files: 1
- file 0 => global file 1
Number of expressions: 0
Number of file 0 mappings: 1
- Code(Zero) at (prev + 26, 1) to (start + 2, 2)
- Code(Zero) at (prev + 25, 1) to (start + 2, 2)

View File

@ -1,11 +1,10 @@
LL| |#![allow(dead_code, unreachable_code)]
LL| |// edition: 2021
LL| |
LL| |// Regression test for #93054: Functions using uninhabited types often only have a single,
LL| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
LL| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
LL| |
LL| |// compile-flags: --edition=2021
LL| |
LL| |enum Never {}
LL| |
LL| |impl Never {

View File

@ -1,11 +1,10 @@
#![allow(dead_code, unreachable_code)]
// edition: 2021
// Regression test for #93054: Functions using uninhabited types often only have a single,
// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
// compile-flags: --edition=2021
enum Never {}
impl Never {

View File

@ -1,4 +1,4 @@
LL| |// compile-flags: --edition=2021
LL| |// edition: 2021
LL| |// ignore-tidy-linelength
LL| |
LL| |// This file deliberately contains line and column numbers larger than 127,

View File

@ -1,4 +1,4 @@
// compile-flags: --edition=2021
// edition: 2021
// ignore-tidy-linelength
// This file deliberately contains line and column numbers larger than 127,

View File

@ -1,4 +1,4 @@
LL| |// compile-flags: --edition=2021
LL| |// edition: 2021
LL| |
LL| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a
LL| |// predictable order, while preserving their heterogeneous contents.

View File

@ -1,4 +1,4 @@
// compile-flags: --edition=2021
// edition: 2021
// Demonstrate that `sort_subviews.py` can sort instantiation groups into a
// predictable order, while preserving their heterogeneous contents.

View File

@ -1,4 +1,4 @@
LL| |// compile-flags: --edition=2021
LL| |// edition: 2021
LL| |
LL| 1|fn main() {}

View File

@ -1,3 +1,3 @@
// compile-flags: --edition=2021
// edition: 2021
fn main() {}

View File

@ -1,6 +1,6 @@
LL| |#![feature(core_intrinsics)]
LL| |#![feature(coverage_attribute)]
LL| |// compile-flags: --edition=2021
LL| |// edition: 2021
LL| |
LL| |// <https://github.com/rust-lang/rust/issues/116171>
LL| |// If we instrument a function for coverage, but all of its counter-increment

View File

@ -1,6 +1,6 @@
#![feature(core_intrinsics)]
#![feature(coverage_attribute)]
// compile-flags: --edition=2021
// edition: 2021
// <https://github.com/rust-lang/rust/issues/116171>
// If we instrument a function for coverage, but all of its counter-increment

View File

@ -19,6 +19,6 @@ use rustc_errors::{Applicability, MultiSpan};
extern crate rustc_session;
#[derive(Diagnostic)]
#[diag(compiletest_example, code = 0123)]
#[diag(compiletest_example, code = E0123)]
//~^ ERROR diagnostic slug and crate name do not match
struct Hello {}

View File

@ -1,7 +1,7 @@
error: diagnostic slug and crate name do not match
--> $DIR/enforce_slug_naming.rs:22:8
|
LL | #[diag(compiletest_example, code = 0123)]
LL | #[diag(compiletest_example, code = E0123)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: slug is `compiletest_example` but the crate name is `rustc_dummy`

View File

@ -143,7 +143,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
LL | target_feature = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt`
= note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt`
= note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`

View File

@ -0,0 +1,5 @@
// Regression test for issue #120615.
fn main() {
[(); loop {}].field; //~ ERROR constant evaluation is taking a long time
}

View File

@ -0,0 +1,17 @@
error: constant evaluation is taking a long time
--> $DIR/field-access-after-const-eval-fail-in-ty.rs:4:10
|
LL | [(); loop {}].field;
| ^^^^^^^
|
= note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval.
If your compilation actually takes a long time, you can safely allow the lint.
help: the constant being evaluated
--> $DIR/field-access-after-const-eval-fail-in-ty.rs:4:10
|
LL | [(); loop {}].field;
| ^^^^^^^
= note: `#[deny(long_running_const_eval)]` on by default
error: aborting due to 1 previous error

View File

@ -0,0 +1,10 @@
fn make<N: u32>() {}
//~^ ERROR expected trait, found builtin type `u32`
//~| HELP you might have meant to write a const parameter here
struct Array<N: usize>([bool; N]);
//~^ ERROR expected trait, found builtin type `usize`
//~| HELP you might have meant to write a const parameter here
//~| ERROR expected value, found type parameter `N`
fn main() {}

View File

@ -0,0 +1,34 @@
error[E0404]: expected trait, found builtin type `u32`
--> $DIR/change-ty-to-const-param-sugg-0.rs:1:12
|
LL | fn make<N: u32>() {}
| ^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | fn make<const N: u32>() {}
| +++++
error[E0404]: expected trait, found builtin type `usize`
--> $DIR/change-ty-to-const-param-sugg-0.rs:5:17
|
LL | struct Array<N: usize>([bool; N]);
| ^^^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | struct Array<const N: usize>([bool; N]);
| +++++
error[E0423]: expected value, found type parameter `N`
--> $DIR/change-ty-to-const-param-sugg-0.rs:5:31
|
LL | struct Array<N: usize>([bool; N]);
| - ^ not a value
| |
| found this type parameter
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0404, E0423.
For more information about an error, try `rustc --explain E0404`.

View File

@ -0,0 +1,24 @@
#![feature(adt_const_params)]
#![allow(incomplete_features)]
use std::marker::ConstParamTy;
struct Tagged<T: Tag, O: Options>;
//~^ ERROR expected trait, found enum `Tag`
//~| HELP you might have meant to write a const parameter here
//~| ERROR expected trait, found struct `Options`
//~| HELP you might have meant to write a const parameter here
#[derive(PartialEq, Eq, ConstParamTy)]
enum Tag {
One,
Two,
}
#[derive(PartialEq, Eq, ConstParamTy)]
struct Options {
verbose: bool,
safe: bool,
}
fn main() {}

View File

@ -0,0 +1,25 @@
error[E0404]: expected trait, found enum `Tag`
--> $DIR/change-ty-to-const-param-sugg-1.rs:6:18
|
LL | struct Tagged<T: Tag, O: Options>;
| ^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | struct Tagged<const T: Tag, O: Options>;
| +++++
error[E0404]: expected trait, found struct `Options`
--> $DIR/change-ty-to-const-param-sugg-1.rs:6:26
|
LL | struct Tagged<T: Tag, O: Options>;
| ^^^^^^^ not a trait
|
help: you might have meant to write a const parameter here
|
LL | struct Tagged<T: Tag, const O: Options>;
| +++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0404`.