Merge from rustc
This commit is contained in:
commit
a1bc030b70
1044 changed files with 18570 additions and 9630 deletions
10
.github/pull_request_template.md
vendored
Normal file
10
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!--
|
||||
If this PR is related to an unstable feature or an otherwise tracked effort,
|
||||
please link to the relevant tracking issue here. If you don't know of a related
|
||||
tracking issue or there are none, feel free to ignore this.
|
||||
|
||||
This PR will get automatically assigned to a reviewer. In case you would like
|
||||
a specific user to review your work, you can assign it to them by using
|
||||
|
||||
r? <reviewer name>
|
||||
-->
|
||||
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
|
@ -190,7 +190,6 @@ jobs:
|
|||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
|
||||
- name: create github artifacts
|
||||
run: src/ci/scripts/create-doc-artifacts.sh
|
||||
|
|
@ -241,3 +240,5 @@ jobs:
|
|||
if: needs.calculate_matrix.outputs.run_type == 'auto'
|
||||
env:
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
|
|
|
|||
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -33,7 +33,7 @@
|
|||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/rust-lang/llvm-project.git
|
||||
branch = rustc/18.0-2024-02-13
|
||||
branch = rustc/18.1-2024-05-19
|
||||
shallow = true
|
||||
[submodule "src/doc/embedded-book"]
|
||||
path = src/doc/embedded-book
|
||||
|
|
@ -43,3 +43,7 @@
|
|||
path = library/backtrace
|
||||
url = https://github.com/rust-lang/backtrace-rs.git
|
||||
shallow = true
|
||||
[submodule "src/tools/rustc-perf"]
|
||||
path = src/tools/rustc-perf
|
||||
url = https://github.com/rust-lang/rustc-perf.git
|
||||
shallow = true
|
||||
|
|
|
|||
593
Cargo.lock
593
Cargo.lock
File diff suppressed because it is too large
Load diff
|
|
@ -2733,6 +2733,13 @@ pub enum UseTreeKind {
|
|||
/// `use prefix` or `use prefix as rename`
|
||||
Simple(Option<Ident>),
|
||||
/// `use prefix::{...}`
|
||||
///
|
||||
/// The span represents the braces of the nested group and all elements within:
|
||||
///
|
||||
/// ```text
|
||||
/// use foo::{bar, baz};
|
||||
/// ^^^^^^^^^^
|
||||
/// ```
|
||||
Nested { items: ThinVec<(UseTree, NodeId)>, span: Span },
|
||||
/// `use prefix::*`
|
||||
Glob,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use crate::util::literal::escape_string_symbol;
|
|||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::iter;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
|
@ -87,10 +88,20 @@ impl Attribute {
|
|||
AttrKind::DocComment(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
}
|
||||
|
||||
pub fn path(&self) -> SmallVec<[Symbol; 1]> {
|
||||
match &self.kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
normal.item.path.segments.iter().map(|s| s.ident.name).collect()
|
||||
}
|
||||
AttrKind::DocComment(..) => smallvec![sym::doc],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_name(&self, name: Symbol) -> bool {
|
||||
match &self.kind {
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ impl<'a, T> IntoIterator for &'a P<[T]> {
|
|||
type Item = &'a T;
|
||||
type IntoIter = slice::Iter<'a, T>;
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.ptr.into_iter()
|
||||
self.ptr.iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,9 +55,6 @@ ast_passes_const_without_body =
|
|||
ast_passes_constraint_on_negative_bound =
|
||||
associated type constraints not allowed on negative bounds
|
||||
|
||||
ast_passes_deprecated_where_clause_location =
|
||||
where clause not allowed here
|
||||
|
||||
ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
|
||||
.label = not supported
|
||||
.suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
|
||||
|
|
@ -80,8 +77,6 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de
|
|||
.suggestion = remove the {$remove_descr}
|
||||
.label = `extern` block begins here
|
||||
|
||||
ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
|
||||
|
||||
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
|
||||
.suggestion = remove the attribute
|
||||
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ use std::ops::{Deref, DerefMut};
|
|||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::errors;
|
||||
use crate::fluent_generated as fluent;
|
||||
|
||||
/// Is `self` allowed semantically as the first parameter in an `FnDecl`?
|
||||
enum SelfSemantic {
|
||||
|
|
@ -766,11 +765,10 @@ impl<'a> AstValidator<'a> {
|
|||
.span_to_snippet(span)
|
||||
.is_ok_and(|snippet| !snippet.starts_with("#["))
|
||||
{
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
self.lint_buffer.buffer_lint(
|
||||
MISSING_ABI,
|
||||
id,
|
||||
span,
|
||||
fluent::ast_passes_extern_without_abi,
|
||||
BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK),
|
||||
)
|
||||
}
|
||||
|
|
@ -1428,17 +1426,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
|
||||
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
|
||||
if let Some(ident) = ident {
|
||||
let msg = match ctxt {
|
||||
FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
|
||||
_ => fluent::ast_passes_pattern_in_bodiless,
|
||||
};
|
||||
let diag = BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident);
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
self.lint_buffer.buffer_lint(
|
||||
PATTERNS_IN_FNS_WITHOUT_BODY,
|
||||
id,
|
||||
span,
|
||||
msg,
|
||||
diag,
|
||||
BuiltinLintDiag::PatternsInFnsWithoutBody {
|
||||
span,
|
||||
ident,
|
||||
is_foreign: matches!(ctxt, FnCtxt::Foreign),
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1510,12 +1506,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
Some((right, snippet))
|
||||
}
|
||||
};
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
self.lint_buffer.buffer_lint(
|
||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||
item.id,
|
||||
err.span,
|
||||
fluent::ast_passes_deprecated_where_clause_location,
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg),
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -669,6 +669,7 @@ pub struct ConstAndCVariadic {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_pattern_in_foreign, code = E0130)]
|
||||
// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
|
||||
pub struct PatternInForeign {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
|
|
@ -677,6 +678,7 @@ pub struct PatternInForeign {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_pattern_in_bodiless, code = E0642)]
|
||||
// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
|
||||
pub struct PatternInBodiless {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
|
|
|
|||
|
|
@ -560,6 +560,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||
gate_all!(postfix_match, "postfix match is experimental");
|
||||
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
|
||||
gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
|
||||
gate_all!(global_registration, "global registration is experimental");
|
||||
|
||||
if !visitor.features.never_patterns {
|
||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||
|
|
|
|||
|
|
@ -528,15 +528,10 @@ pub fn cfg_matches(
|
|||
try_gate_cfg(cfg.name, cfg.span, sess, features);
|
||||
match sess.psess.check_config.expecteds.get(&cfg.name) {
|
||||
Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
sess.psess.buffer_lint(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
if let Some(value) = cfg.value {
|
||||
format!("unexpected `cfg` condition value: `{value}`")
|
||||
} else {
|
||||
format!("unexpected `cfg` condition value: (none)")
|
||||
},
|
||||
BuiltinLintDiag::UnexpectedCfgValue(
|
||||
(cfg.name, cfg.name_span),
|
||||
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||
|
|
@ -544,11 +539,10 @@ pub fn cfg_matches(
|
|||
);
|
||||
}
|
||||
None if sess.psess.check_config.exhaustive_names => {
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
sess.psess.buffer_lint(
|
||||
UNEXPECTED_CFGS,
|
||||
cfg.span,
|
||||
lint_node_id,
|
||||
format!("unexpected `cfg` condition name: `{}`", cfg.name),
|
||||
BuiltinLintDiag::UnexpectedCfgName(
|
||||
(cfg.name, cfg.name_span),
|
||||
cfg.value.map(|v| (v, cfg.value_span.unwrap())),
|
||||
|
|
|
|||
|
|
@ -652,7 +652,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
// FIXME: We make sure that this is a normal top-level binding,
|
||||
// but we could suggest `todo!()` for all uninitialized bindings in the pattern pattern
|
||||
// but we could suggest `todo!()` for all uninitialized bindings in the pattern
|
||||
if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =
|
||||
&ex.kind
|
||||
&& let hir::PatKind::Binding(..) = pat.kind
|
||||
|
|
@ -3343,6 +3343,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
} else if string.starts_with("gen") {
|
||||
// `gen` is 3 chars long
|
||||
Some(3)
|
||||
} else if string.starts_with("static") {
|
||||
// `static` is 6 chars long
|
||||
// This is used for `!Unpin` coroutines
|
||||
Some(6)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
|||
|
|
@ -992,7 +992,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if look_at_return && hir.get_return_block(closure_id).is_some() {
|
||||
if look_at_return && hir.get_fn_id_for_return_block(closure_id).is_some() {
|
||||
// ...otherwise we are probably in the tail expression of the function, point at the
|
||||
// return type.
|
||||
match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,31 @@ use std::path::Path;
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RustcFacts;
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// A (kinda) newtype of `RegionVid` so we can implement `Atom` on it.
|
||||
#[orderable]
|
||||
#[debug_format = "'?{}"]
|
||||
pub struct PoloniusRegionVid {}
|
||||
}
|
||||
|
||||
impl polonius_engine::Atom for PoloniusRegionVid {
|
||||
fn index(self) -> usize {
|
||||
self.as_usize()
|
||||
}
|
||||
}
|
||||
impl From<RegionVid> for PoloniusRegionVid {
|
||||
fn from(value: RegionVid) -> Self {
|
||||
Self::from_usize(value.as_usize())
|
||||
}
|
||||
}
|
||||
impl From<PoloniusRegionVid> for RegionVid {
|
||||
fn from(value: PoloniusRegionVid) -> Self {
|
||||
Self::from_usize(value.as_usize())
|
||||
}
|
||||
}
|
||||
|
||||
impl polonius_engine::FactTypes for RustcFacts {
|
||||
type Origin = RegionVid;
|
||||
type Origin = PoloniusRegionVid;
|
||||
type Loan = BorrowIndex;
|
||||
type Point = LocationIndex;
|
||||
type Variable = Local;
|
||||
|
|
@ -119,7 +142,7 @@ trait FactRow {
|
|||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl FactRow for RegionVid {
|
||||
impl FactRow for PoloniusRegionVid {
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
|
|
|
|||
|
|
@ -1312,8 +1312,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
|
||||
| Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
self.consume_operand(location, (operand1, span), flow_state);
|
||||
self.consume_operand(location, (operand2, span), flow_state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,8 +302,7 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
|
||||
| Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
|
||||
self.consume_operand(location, operand1);
|
||||
self.consume_operand(location, operand2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::facts::AllFacts;
|
||||
use crate::facts::{AllFacts, PoloniusRegionVid};
|
||||
use crate::location::LocationTable;
|
||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
|
@ -137,7 +137,9 @@ fn emit_universal_region_facts(
|
|||
// the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
|
||||
// added to the existing number of loans, as if they succeeded them in the set.
|
||||
//
|
||||
all_facts.universal_region.extend(universal_regions.universal_regions());
|
||||
all_facts
|
||||
.universal_region
|
||||
.extend(universal_regions.universal_regions().map(PoloniusRegionVid::from));
|
||||
let borrow_count = borrow_set.len();
|
||||
debug!(
|
||||
"emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
|
||||
|
|
@ -148,7 +150,7 @@ fn emit_universal_region_facts(
|
|||
for universal_region in universal_regions.universal_regions() {
|
||||
let universal_region_idx = universal_region.index();
|
||||
let placeholder_loan_idx = borrow_count + universal_region_idx;
|
||||
all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
|
||||
all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
|
||||
}
|
||||
|
||||
// 2: the universal region relations `outlives` constraints are emitted as
|
||||
|
|
@ -160,7 +162,7 @@ fn emit_universal_region_facts(
|
|||
fr1={:?}, fr2={:?}",
|
||||
fr1, fr2
|
||||
);
|
||||
all_facts.known_placeholder_subset.push((fr1, fr2));
|
||||
all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1506,7 +1506,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
subset_errors.sort();
|
||||
subset_errors.dedup();
|
||||
|
||||
for (longer_fr, shorter_fr) in subset_errors.into_iter() {
|
||||
for &(longer_fr, shorter_fr) in subset_errors.into_iter() {
|
||||
debug!(
|
||||
"check_polonius_subset_errors: subset_error longer_fr={:?},\
|
||||
shorter_fr={:?}",
|
||||
|
|
@ -1514,14 +1514,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
);
|
||||
|
||||
let propagated = self.try_propagate_universal_region_error(
|
||||
*longer_fr,
|
||||
*shorter_fr,
|
||||
longer_fr.into(),
|
||||
shorter_fr.into(),
|
||||
&mut propagated_outlives_requirements,
|
||||
);
|
||||
if propagated == RegionRelationCheckResult::Error {
|
||||
errors_buffer.push(RegionErrorKind::RegionError {
|
||||
longer_fr: *longer_fr,
|
||||
shorter_fr: *shorter_fr,
|
||||
longer_fr: longer_fr.into(),
|
||||
shorter_fr: shorter_fr.into(),
|
||||
fr_origin: NllRegionVariableOrigin::FreeRegion,
|
||||
is_reported: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ pub(super) fn populate_access_facts<'a, 'tcx>(
|
|||
let universal_regions = &typeck.borrowck_context.universal_regions;
|
||||
typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
|
||||
let region_vid = universal_regions.to_region_vid(region);
|
||||
facts.use_of_var_derefs_origin.push((local, region_vid));
|
||||
facts.use_of_var_derefs_origin.push((local, region_vid.into()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ pub(super) fn add_drop_of_var_derefs_origin<'tcx>(
|
|||
let universal_regions = &typeck.borrowck_context.universal_regions;
|
||||
typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
|
||||
let region_vid = universal_regions.to_region_vid(drop_live_region);
|
||||
facts.drop_of_var_derefs_origin.push((local, region_vid));
|
||||
facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -260,16 +260,14 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
|
|||
|constraint: &OutlivesConstraint<'_>| {
|
||||
if let Some(from_location) = constraint.locations.from_location() {
|
||||
Either::Left(iter::once((
|
||||
constraint.sup,
|
||||
constraint.sub,
|
||||
constraint.sup.into(),
|
||||
constraint.sub.into(),
|
||||
location_table.mid_index(from_location),
|
||||
)))
|
||||
} else {
|
||||
Either::Right(
|
||||
location_table
|
||||
.all_points()
|
||||
.map(move |location| (constraint.sup, constraint.sub, location)),
|
||||
)
|
||||
Either::Right(location_table.all_points().map(move |location| {
|
||||
(constraint.sup.into(), constraint.sub.into(), location)
|
||||
}))
|
||||
}
|
||||
},
|
||||
));
|
||||
|
|
@ -2417,8 +2415,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.check_operand(op, location);
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(_, box (left, right))
|
||||
| Rvalue::CheckedBinaryOp(_, box (left, right)) => {
|
||||
Rvalue::BinaryOp(_, box (left, right)) => {
|
||||
self.check_operand(left, location);
|
||||
self.check_operand(right, location);
|
||||
}
|
||||
|
|
@ -2445,7 +2442,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
| Rvalue::Cast(..)
|
||||
| Rvalue::ShallowInitBox(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
| Rvalue::NullaryOp(..)
|
||||
| Rvalue::CopyForDeref(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
|
|
@ -2547,7 +2543,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
|
||||
let region_vid = borrow_region.as_var();
|
||||
all_facts.loan_issued_at.push((
|
||||
region_vid,
|
||||
region_vid.into(),
|
||||
borrow_index,
|
||||
location_table.mid_index(location),
|
||||
));
|
||||
|
|
|
|||
|
|
@ -247,5 +247,3 @@ builtin_macros_unexpected_lit = expected path to a trait, found literal
|
|||
.label = not a trait
|
||||
.str_lit = try using `#[derive({$sym})]`
|
||||
.other = for example, write `#[derive(Debug)]` for `Debug`
|
||||
|
||||
builtin_macros_unnameable_test_items = cannot test inner items
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::errors;
|
||||
use crate::util::expr_to_spanned_string;
|
||||
use ast::token::IdentIsRaw;
|
||||
use lint::BuiltinLintDiag;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter};
|
||||
|
|
@ -513,7 +514,7 @@ fn expand_preparsed_asm(
|
|||
lint::builtin::BAD_ASM_STYLE,
|
||||
find_span(".intel_syntax"),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
"avoid using `.intel_syntax`, Intel syntax is the default",
|
||||
BuiltinLintDiag::AvoidUsingIntelSyntax,
|
||||
);
|
||||
}
|
||||
if template_str.contains(".att_syntax") {
|
||||
|
|
@ -521,7 +522,7 @@ fn expand_preparsed_asm(
|
|||
lint::builtin::BAD_ASM_STYLE,
|
||||
find_span(".att_syntax"),
|
||||
ecx.current_expansion.lint_node_id,
|
||||
"avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
|
||||
BuiltinLintDiag::AvoidUsingAttSyntax,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1621,14 +1621,13 @@ impl<'a> TraitDef<'a> {
|
|||
};
|
||||
|
||||
if let Some(ty) = exception {
|
||||
cx.sess.psess.buffer_lint_with_diagnostic(
|
||||
cx.sess.psess.buffer_lint(
|
||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||
sp,
|
||||
ast::CRATE_NODE_ID,
|
||||
format!(
|
||||
"{ty} slice in a packed struct that derives a built-in trait"
|
||||
),
|
||||
rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive,
|
||||
rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive {
|
||||
ty: ty.to_string(),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// Wrap the expression in `{...}`, causing a copy.
|
||||
|
|
|
|||
|
|
@ -556,7 +556,6 @@ fn make_format_args(
|
|||
let arg_name = args.explicit_args()[index].kind.ident().unwrap();
|
||||
ecx.buffered_early_lint.push(BufferedEarlyLint {
|
||||
span: arg_name.span.into(),
|
||||
msg: format!("named argument `{}` is not used by name", arg_name.name).into(),
|
||||
node_id: rustc_ast::CRATE_NODE_ID,
|
||||
lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
|
||||
diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use rustc_expand::base::{
|
|||
resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult,
|
||||
};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::new_parser_from_file;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
|
|
@ -147,7 +148,7 @@ pub(crate) fn expand_include<'cx>(
|
|||
INCOMPLETE_INCLUDE,
|
||||
self.p.token.span,
|
||||
self.node_id,
|
||||
"include macro expected single expression in source",
|
||||
BuiltinLintDiag::IncompleteInclude,
|
||||
);
|
||||
}
|
||||
Some(expr)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_ast::{attr, ModKind};
|
|||
use rustc_expand::base::{ExtCtxt, ResolverExpand};
|
||||
use rustc_expand::expand::{AstFragment, ExpansionConfig};
|
||||
use rustc_feature::Features;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
|
||||
|
|
@ -163,7 +164,7 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> {
|
|||
UNNAMEABLE_TEST_ITEMS,
|
||||
attr.span,
|
||||
i.id,
|
||||
crate::fluent_generated::builtin_macros_unnameable_test_items,
|
||||
BuiltinLintDiag::UnnameableTestItems,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
|
|||
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
|
||||
use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag};
|
||||
use rustc_parse::{parser, validate_attr};
|
||||
use rustc_session::errors::report_lit_error;
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
|
|
@ -46,7 +46,7 @@ pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable,
|
|||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
attr.span,
|
||||
ecx.current_expansion.lint_node_id,
|
||||
"duplicated attribute",
|
||||
BuiltinLintDiag::DuplicateMacroAttribute,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -609,14 +609,11 @@ fn codegen_stmt<'tcx>(
|
|||
let lhs = codegen_operand(fx, &lhs_rhs.0);
|
||||
let rhs = codegen_operand(fx, &lhs_rhs.1);
|
||||
|
||||
let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
|
||||
lval.write_cvalue(fx, res);
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => {
|
||||
let lhs = codegen_operand(fx, &lhs_rhs.0);
|
||||
let rhs = codegen_operand(fx, &lhs_rhs.1);
|
||||
|
||||
let res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
|
||||
let res = if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
|
||||
crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
|
||||
} else {
|
||||
crate::num::codegen_binop(fx, bin_op, lhs, rhs)
|
||||
};
|
||||
lval.write_cvalue(fx, res);
|
||||
}
|
||||
Rvalue::UnaryOp(un_op, ref operand) => {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ pub(crate) fn maybe_codegen<'tcx>(
|
|||
}
|
||||
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
|
||||
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
|
||||
BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +133,7 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
Some(out_place.to_cvalue(fx))
|
||||
}
|
||||
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
|
||||
BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
|
||||
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
|
||||
BinOp::Div | BinOp::Rem => unreachable!(),
|
||||
BinOp::Cmp => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -348,6 +348,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
| sym::simd_bswap
|
||||
| sym::simd_bitreverse
|
||||
| sym::simd_ctlz
|
||||
| sym::simd_ctpop
|
||||
| sym::simd_cttz => {
|
||||
intrinsic_args!(fx, args => (a); intrinsic);
|
||||
|
||||
|
|
@ -367,6 +368,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
(ty::Uint(_) | ty::Int(_), sym::simd_bswap) => fx.bcx.ins().bswap(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_bitreverse) => fx.bcx.ins().bitrev(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_ctlz) => fx.bcx.ins().clz(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_ctpop) => fx.bcx.ins().popcnt(lane),
|
||||
(ty::Uint(_) | ty::Int(_), sym::simd_cttz) => fx.bcx.ins().ctz(lane),
|
||||
|
||||
_ => unreachable!(),
|
||||
|
|
|
|||
|
|
@ -179,6 +179,9 @@ pub(crate) fn codegen_int_binop<'tcx>(
|
|||
}
|
||||
}
|
||||
BinOp::Offset => unreachable!("Offset is not an integer operation"),
|
||||
BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => {
|
||||
unreachable!("Overflow binops handled by `codegen_checked_int_binop`")
|
||||
}
|
||||
// Compare binops handles by `codegen_binop`.
|
||||
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
|
||||
unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
|
||||
|
|
|
|||
|
|
@ -200,21 +200,20 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
|
|||
_ => panic!("unsupported arch {}", sess.target.arch),
|
||||
};
|
||||
let mut dlltool_cmd = std::process::Command::new(&dlltool);
|
||||
dlltool_cmd.args([
|
||||
"-d",
|
||||
def_file_path.to_str().unwrap(),
|
||||
"-D",
|
||||
lib_name,
|
||||
"-l",
|
||||
output_path.to_str().unwrap(),
|
||||
"-m",
|
||||
dlltool_target_arch,
|
||||
"-f",
|
||||
dlltool_target_bitness,
|
||||
"--no-leading-underscore",
|
||||
"--temp-prefix",
|
||||
temp_prefix.to_str().unwrap(),
|
||||
]);
|
||||
dlltool_cmd
|
||||
.arg("-d")
|
||||
.arg(def_file_path)
|
||||
.arg("-D")
|
||||
.arg(lib_name)
|
||||
.arg("-l")
|
||||
.arg(&output_path)
|
||||
.arg("-m")
|
||||
.arg(dlltool_target_arch)
|
||||
.arg("-f")
|
||||
.arg(dlltool_target_bitness)
|
||||
.arg("--no-leading-underscore")
|
||||
.arg("--temp-prefix")
|
||||
.arg(temp_prefix);
|
||||
|
||||
match dlltool_cmd.output() {
|
||||
Err(e) => {
|
||||
|
|
|
|||
|
|
@ -2336,7 +2336,10 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}
|
||||
|
||||
// Unary integer intrinsics
|
||||
if matches!(name, sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_cttz) {
|
||||
if matches!(
|
||||
name,
|
||||
sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop | sym::simd_cttz
|
||||
) {
|
||||
let vec_ty = bx.cx.type_vector(
|
||||
match *in_elem.kind() {
|
||||
ty::Int(i) => bx.cx.type_int_from_ty(i),
|
||||
|
|
@ -2354,31 +2357,38 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
sym::simd_bswap => "bswap",
|
||||
sym::simd_bitreverse => "bitreverse",
|
||||
sym::simd_ctlz => "ctlz",
|
||||
sym::simd_ctpop => "ctpop",
|
||||
sym::simd_cttz => "cttz",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
|
||||
let llvm_intrinsic = &format!("llvm.{}.v{}i{}", intrinsic_name, in_len, int_size,);
|
||||
|
||||
return if name == sym::simd_bswap && int_size == 8 {
|
||||
return match name {
|
||||
// byte swap is no-op for i8/u8
|
||||
Ok(args[0].immediate())
|
||||
} else if matches!(name, sym::simd_ctlz | sym::simd_cttz) {
|
||||
let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
Ok(bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
&[args[0].immediate(), bx.const_int(bx.type_i1(), 0)],
|
||||
None,
|
||||
None,
|
||||
))
|
||||
} else {
|
||||
let fn_ty = bx.type_func(&[vec_ty], vec_ty);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
|
||||
sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()),
|
||||
sym::simd_ctlz | sym::simd_cttz => {
|
||||
// for the (int, i1 immediate) pair, the second arg adds `(0, true) => poison`
|
||||
let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
|
||||
let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
Ok(bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
&[args[0].immediate(), dont_poison_on_zero],
|
||||
None,
|
||||
None,
|
||||
))
|
||||
}
|
||||
sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => {
|
||||
// simple unary argument cases
|
||||
let fn_ty = bx.type_func(&[vec_ty], vec_ty);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1230,7 +1230,10 @@ fn add_sanitizer_libraries(
|
|||
if sanitizer.contains(SanitizerSet::DATAFLOW) {
|
||||
link_sanitizer_runtime(sess, flavor, linker, "dfsan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::LEAK) {
|
||||
if sanitizer.contains(SanitizerSet::LEAK)
|
||||
&& !sanitizer.contains(SanitizerSet::ADDRESS)
|
||||
&& !sanitizer.contains(SanitizerSet::HWADDRESS)
|
||||
{
|
||||
link_sanitizer_runtime(sess, flavor, linker, "lsan");
|
||||
}
|
||||
if sanitizer.contains(SanitizerSet::MEMORY) {
|
||||
|
|
|
|||
|
|
@ -576,6 +576,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
|
||||
if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
|
||||
{
|
||||
let lhs = self.codegen_operand(bx, lhs);
|
||||
let rhs = self.codegen_operand(bx, rhs);
|
||||
let result = self.codegen_scalar_checked_binop(
|
||||
bx,
|
||||
op,
|
||||
lhs.immediate(),
|
||||
rhs.immediate(),
|
||||
lhs.layout.ty,
|
||||
);
|
||||
let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
|
||||
let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
|
||||
OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
|
||||
}
|
||||
mir::Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
|
||||
let lhs = self.codegen_operand(bx, lhs);
|
||||
let rhs = self.codegen_operand(bx, rhs);
|
||||
|
|
@ -604,20 +620,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
layout: bx.cx().layout_of(op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)),
|
||||
}
|
||||
}
|
||||
mir::Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
|
||||
let lhs = self.codegen_operand(bx, lhs);
|
||||
let rhs = self.codegen_operand(bx, rhs);
|
||||
let result = self.codegen_scalar_checked_binop(
|
||||
bx,
|
||||
op,
|
||||
lhs.immediate(),
|
||||
rhs.immediate(),
|
||||
lhs.layout.ty,
|
||||
);
|
||||
let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
|
||||
let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
|
||||
OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
|
||||
}
|
||||
|
||||
mir::Rvalue::UnaryOp(op, ref operand) => {
|
||||
let operand = self.codegen_operand(bx, operand);
|
||||
|
|
@ -928,6 +930,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
|
||||
}
|
||||
}
|
||||
mir::BinOp::AddWithOverflow
|
||||
| mir::BinOp::SubWithOverflow
|
||||
| mir::BinOp::MulWithOverflow => {
|
||||
bug!("{op:?} needs to return a pair, so call codegen_scalar_checked_binop instead")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1040,7 +1047,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
mir::Rvalue::Cast(..) | // (*)
|
||||
mir::Rvalue::ShallowInitBox(..) | // (*)
|
||||
mir::Rvalue::BinaryOp(..) |
|
||||
mir::Rvalue::CheckedBinaryOp(..) |
|
||||
mir::Rvalue::UnaryOp(..) |
|
||||
mir::Rvalue::Discriminant(..) |
|
||||
mir::Rvalue::NullaryOp(..) |
|
||||
|
|
|
|||
|
|
@ -167,15 +167,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
|
||||
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
|
||||
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
|
||||
self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
|
||||
}
|
||||
|
||||
CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
|
||||
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
|
||||
let left = self.read_immediate(&self.eval_operand(left, None)?)?;
|
||||
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
|
||||
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
|
||||
self.binop_with_overflow(bin_op, &left, &right, &dest)?;
|
||||
if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
|
||||
self.binop_with_overflow(bin_op, &left, &right, &dest)?;
|
||||
} else {
|
||||
self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
UnaryOp(un_op, ref operand) => {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
/*!
|
||||
|
||||
Rust MIR: a lowered representation of Rust.
|
||||
|
||||
*/
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![feature(rustdoc_internals)]
|
||||
|
|
|
|||
|
|
@ -580,7 +580,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
|
||||
Rvalue::BinaryOp(op, box (lhs, rhs)) => {
|
||||
let lhs_ty = lhs.ty(self.body, self.tcx);
|
||||
let rhs_ty = rhs.ty(self.body, self.tcx);
|
||||
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ where
|
|||
| Rvalue::Cast(_, operand, _)
|
||||
| Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
|
||||
|
||||
Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
|
||||
Rvalue::BinaryOp(_, box (lhs, rhs)) => {
|
||||
in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -200,7 +200,6 @@ where
|
|||
| mir::Rvalue::Repeat(..)
|
||||
| mir::Rvalue::Len(..)
|
||||
| mir::Rvalue::BinaryOp(..)
|
||||
| mir::Rvalue::CheckedBinaryOp(..)
|
||||
| mir::Rvalue::NullaryOp(..)
|
||||
| mir::Rvalue::UnaryOp(..)
|
||||
| mir::Rvalue::Discriminant(..)
|
||||
|
|
|
|||
|
|
@ -1037,8 +1037,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
)
|
||||
}
|
||||
}
|
||||
AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
|
||||
| ShrUnchecked => {
|
||||
AddUnchecked | AddWithOverflow | SubUnchecked | SubWithOverflow
|
||||
| MulUnchecked | MulWithOverflow | Shl | ShlUnchecked | Shr | ShrUnchecked => {
|
||||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
|
|
@ -1067,31 +1067,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(op, vals) => {
|
||||
use BinOp::*;
|
||||
let a = vals.0.ty(&self.body.local_decls, self.tcx);
|
||||
let b = vals.1.ty(&self.body.local_decls, self.tcx);
|
||||
match op {
|
||||
Add | Sub | Mul => {
|
||||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot perform checked arithmetic on type {:?}",
|
||||
ty::Uint(..) | ty::Int(..)
|
||||
)
|
||||
}
|
||||
if a != b {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"Cannot perform checked arithmetic on unequal types {a:?} and {b:?}"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => self.fail(location, format!("There is no checked version of {op:?}")),
|
||||
}
|
||||
}
|
||||
Rvalue::UnaryOp(op, operand) => {
|
||||
let a = operand.ty(&self.body.local_decls, self.tcx);
|
||||
match op {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
|
|||
match op {
|
||||
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
|
||||
| BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
|
||||
Eq | Ne | Lt | Le | Gt | Ge | Cmp => false,
|
||||
AddWithOverflow | SubWithOverflow | MulWithOverflow | Eq | Ne | Lt | Le | Gt | Ge | Cmp => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -29,8 +31,9 @@ pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
|
|||
pub fn binop_right_homogeneous(op: mir::BinOp) -> bool {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
match op {
|
||||
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
|
||||
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge | Cmp => true,
|
||||
Add | AddUnchecked | AddWithOverflow | Sub | SubUnchecked | SubWithOverflow | Mul
|
||||
| MulUnchecked | MulWithOverflow | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt
|
||||
| Le | Gt | Ge | Cmp => true,
|
||||
Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,6 +282,12 @@ impl IntoDiagArg for ClosureKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoDiagArg for hir::def::Namespace {
|
||||
fn into_diag_arg(self) -> DiagArgValue {
|
||||
DiagArgValue::Str(Cow::Borrowed(self.descr()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DiagSymbolList(Vec<Symbol>);
|
||||
|
||||
|
|
|
|||
|
|
@ -1364,18 +1364,15 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
|
|||
};
|
||||
|
||||
if crate_matches {
|
||||
// FIXME: make this translatable
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
PROC_MACRO_BACK_COMPAT,
|
||||
item.ident.span,
|
||||
ast::CRATE_NODE_ID,
|
||||
"using an old version of `rental`",
|
||||
BuiltinLintDiag::ProcMacroBackCompat(
|
||||
"older versions of the `rental` crate will stop compiling in future versions of Rust; \
|
||||
please update to `rental` v0.5.6, or switch to one of the `rental` alternatives".to_string()
|
||||
)
|
||||
);
|
||||
sess.psess.buffer_lint(
|
||||
PROC_MACRO_BACK_COMPAT,
|
||||
item.ident.span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::ProcMacroBackCompat {
|
||||
crate_name: "rental".to_string(),
|
||||
fixed_version: "0.5.6".to_string(),
|
||||
},
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use rustc_attr as attr;
|
|||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_feature::Features;
|
||||
use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES};
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_parse::validate_attr;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
|
|
@ -248,7 +249,6 @@ impl<'a> StripUnconfigured<'a> {
|
|||
/// Gives a compiler warning when the `cfg_attr` contains no attributes and
|
||||
/// is in the original source file. Gives a compiler error if the syntax of
|
||||
/// the attribute is incorrect.
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
|
||||
let Some((cfg_predicate, expanded_attrs)) =
|
||||
rustc_parse::parse_cfg_attr(attr, &self.sess.psess)
|
||||
|
|
@ -262,7 +262,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
|
||||
attr.span,
|
||||
ast::CRATE_NODE_ID,
|
||||
"`#[cfg_attr]` does not expand to any attributes",
|
||||
BuiltinLintDiag::CfgAttrNoAttributes,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +283,6 @@ impl<'a> StripUnconfigured<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
fn expand_cfg_attr_item(
|
||||
&self,
|
||||
attr: &Attribute,
|
||||
|
|
@ -346,7 +345,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||
attr.span,
|
||||
ast::CRATE_NODE_ID,
|
||||
"`crate_type` within an `#![cfg_attr] attribute is deprecated`",
|
||||
BuiltinLintDiag::CrateTypeInCfgAttr,
|
||||
);
|
||||
}
|
||||
if attr.has_name(sym::crate_name) {
|
||||
|
|
@ -354,7 +353,7 @@ impl<'a> StripUnconfigured<'a> {
|
|||
rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||
attr.span,
|
||||
ast::CRATE_NODE_ID,
|
||||
"`crate_name` within an `#![cfg_attr] attribute is deprecated`",
|
||||
BuiltinLintDiag::CrateNameInCfgAttr,
|
||||
);
|
||||
}
|
||||
attr
|
||||
|
|
|
|||
|
|
@ -1799,11 +1799,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
}
|
||||
|
||||
if attr.is_doc_comment() {
|
||||
self.cx.sess.psess.buffer_lint_with_diagnostic(
|
||||
self.cx.sess.psess.buffer_lint(
|
||||
UNUSED_DOC_COMMENTS,
|
||||
current_span,
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
"unused doc comment",
|
||||
BuiltinLintDiag::UnusedDocComment(attr.span),
|
||||
);
|
||||
} else if rustc_attr::is_builtin_attr(attr) {
|
||||
|
|
@ -1811,11 +1810,10 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
// `#[cfg]` and `#[cfg_attr]` are special - they are
|
||||
// eagerly evaluated.
|
||||
if attr_name != sym::cfg && attr_name != sym::cfg_attr {
|
||||
self.cx.sess.psess.buffer_lint_with_diagnostic(
|
||||
self.cx.sess.psess.buffer_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
attr.span,
|
||||
self.cx.current_expansion.lint_node_id,
|
||||
format!("unused attribute `{attr_name}`"),
|
||||
BuiltinLintDiag::UnusedBuiltinAttribute {
|
||||
attr_name,
|
||||
macro_name: pprust::path_to_string(&call.path),
|
||||
|
|
|
|||
|
|
@ -110,7 +110,8 @@ use crate::mbe::{KleeneToken, TokenTree};
|
|||
use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::{NodeId, DUMMY_NODE_ID};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{DiagMessage, MultiSpan};
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::symbol::kw;
|
||||
|
|
@ -252,7 +253,7 @@ fn check_binders(
|
|||
// 1. The meta-variable is already bound in the current LHS: This is an error.
|
||||
let mut span = MultiSpan::from_span(span);
|
||||
span.push_span_label(prev_info.span, "previous declaration");
|
||||
buffer_lint(psess, span, node_id, "duplicate matcher binding");
|
||||
buffer_lint(psess, span, node_id, BuiltinLintDiag::DuplicateMatcherBinding);
|
||||
} else if get_binder_info(macros, binders, name).is_none() {
|
||||
// 2. The meta-variable is free: This is a binder.
|
||||
binders.insert(name, BinderInfo { span, ops: ops.into() });
|
||||
|
|
@ -271,7 +272,7 @@ fn check_binders(
|
|||
MISSING_FRAGMENT_SPECIFIER,
|
||||
span,
|
||||
node_id,
|
||||
"missing fragment specifier",
|
||||
BuiltinLintDiag::MissingFragmentSpecifier,
|
||||
);
|
||||
}
|
||||
if !macros.is_empty() {
|
||||
|
|
@ -595,7 +596,7 @@ fn check_ops_is_prefix(
|
|||
return;
|
||||
}
|
||||
}
|
||||
buffer_lint(psess, span.into(), node_id, format!("unknown macro variable `{name}`"));
|
||||
buffer_lint(psess, span.into(), node_id, BuiltinLintDiag::UnknownMacroVariable(name));
|
||||
}
|
||||
|
||||
/// Returns whether `binder_ops` is a prefix of `occurrence_ops`.
|
||||
|
|
@ -628,8 +629,7 @@ fn ops_is_prefix(
|
|||
if i >= occurrence_ops.len() {
|
||||
let mut span = MultiSpan::from_span(span);
|
||||
span.push_span_label(binder.span, "expected repetition");
|
||||
let message = format!("variable '{name}' is still repeating at this depth");
|
||||
buffer_lint(psess, span, node_id, message);
|
||||
buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableStillRepeating(name));
|
||||
return;
|
||||
}
|
||||
let occurrence = &occurrence_ops[i];
|
||||
|
|
@ -637,21 +637,15 @@ fn ops_is_prefix(
|
|||
let mut span = MultiSpan::from_span(span);
|
||||
span.push_span_label(binder.span, "expected repetition");
|
||||
span.push_span_label(occurrence.span, "conflicting repetition");
|
||||
let message = "meta-variable repeats with different Kleene operator";
|
||||
buffer_lint(psess, span, node_id, message);
|
||||
buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableWrongOperator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn buffer_lint(
|
||||
psess: &ParseSess,
|
||||
span: MultiSpan,
|
||||
node_id: NodeId,
|
||||
message: impl Into<DiagMessage>,
|
||||
) {
|
||||
fn buffer_lint(psess: &ParseSess, span: MultiSpan, node_id: NodeId, diag: BuiltinLintDiag) {
|
||||
// Macros loaded from other crates have dummy node ids.
|
||||
if node_id != DUMMY_NODE_ID {
|
||||
psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, message);
|
||||
psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, diag);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,11 +79,10 @@ impl<'a> ParserAnyMacro<'a> {
|
|||
// but `m!()` is allowed in expression positions (cf. issue #34706).
|
||||
if kind == AstFragmentKind::Expr && parser.token == token::Semi {
|
||||
if is_local {
|
||||
parser.psess.buffer_lint_with_diagnostic(
|
||||
parser.psess.buffer_lint(
|
||||
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
|
||||
parser.token.span,
|
||||
lint_node_id,
|
||||
"trailing semicolon in macro used in expression position",
|
||||
BuiltinLintDiag::TrailingMacro(is_trailing_mac, macro_ident),
|
||||
);
|
||||
}
|
||||
|
|
@ -1154,11 +1153,10 @@ fn check_matcher_core<'tt>(
|
|||
name,
|
||||
Some(NonterminalKind::PatParam { inferred: false }),
|
||||
));
|
||||
sess.psess.buffer_lint_with_diagnostic(
|
||||
sess.psess.buffer_lint(
|
||||
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
"the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",
|
||||
BuiltinLintDiag::OrPatternsBackCompat(span, suggestion),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -515,12 +515,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
EncodeCrossCrate::Yes, experimental!(deprecated_safe),
|
||||
),
|
||||
|
||||
// RFC 2397
|
||||
gated!(
|
||||
do_not_recommend, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes, experimental!(do_not_recommend)
|
||||
),
|
||||
|
||||
// `#[cfi_encoding = ""]`
|
||||
gated!(
|
||||
cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
|
||||
|
|
@ -899,10 +893,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_skip_array_during_method_dispatch, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::No,
|
||||
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
|
||||
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
|
||||
rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
|
||||
from method dispatch when the receiver is of the following type, for compatibility in \
|
||||
editions < 2021 (array) or editions < 2024 (boxed_slice)."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
|
||||
|
|
|
|||
|
|
@ -489,6 +489,8 @@ declare_features! (
|
|||
(incomplete, generic_const_exprs, "1.56.0", Some(76560)),
|
||||
/// Allows generic parameters and where-clauses on free & associated const items.
|
||||
(incomplete, generic_const_items, "1.73.0", Some(113521)),
|
||||
/// Allows registering static items globally, possibly across crates, to iterate over at runtime.
|
||||
(unstable, global_registration, "CURRENT_RUSTC_VERSION", Some(125119)),
|
||||
/// Allows using `..=X` as a patterns in slices.
|
||||
(unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
|
||||
/// Allows `if let` guard in match arms.
|
||||
|
|
|
|||
|
|
@ -607,6 +607,7 @@ pub fn check_intrinsic_type(
|
|||
| sym::simd_bitreverse
|
||||
| sym::simd_ctlz
|
||||
| sym::simd_cttz
|
||||
| sym::simd_ctpop
|
||||
| sym::simd_fsqrt
|
||||
| sym::simd_fsin
|
||||
| sym::simd_fcos
|
||||
|
|
|
|||
|
|
@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
|
|||
}
|
||||
let gat_generics = tcx.generics_of(gat_def_id);
|
||||
// FIXME(jackh726): we can also warn in the more general case
|
||||
if gat_generics.own_params.is_empty() {
|
||||
if gat_generics.is_own_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1117,8 +1117,24 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
|
||||
let is_marker = tcx.has_attr(def_id, sym::marker);
|
||||
let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
|
||||
let skip_array_during_method_dispatch =
|
||||
tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);
|
||||
|
||||
// FIXME: We could probably do way better attribute validation here.
|
||||
let mut skip_array_during_method_dispatch = false;
|
||||
let mut skip_boxed_slice_during_method_dispatch = false;
|
||||
for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
|
||||
if let Some(lst) = attr.meta_item_list() {
|
||||
for item in lst {
|
||||
if let Some(ident) = item.ident() {
|
||||
match ident.as_str() {
|
||||
"array" => skip_array_during_method_dispatch = true,
|
||||
"boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
|
||||
ty::trait_def::TraitSpecializationKind::Marker
|
||||
} else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
|
||||
|
|
@ -1253,6 +1269,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
is_marker,
|
||||
is_coinductive: rustc_coinductive || is_auto,
|
||||
skip_array_during_method_dispatch,
|
||||
skip_boxed_slice_during_method_dispatch,
|
||||
specialization_kind,
|
||||
must_implement_one_of,
|
||||
implement_via_object,
|
||||
|
|
|
|||
|
|
@ -1409,7 +1409,7 @@ fn generics_args_err_extend<'a>(
|
|||
// it was done based on the end of assoc segment but that sometimes
|
||||
// led to impossible spans and caused issues like #116473
|
||||
let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
|
||||
if tcx.generics_of(adt_def.did()).count() == 0 {
|
||||
if tcx.generics_of(adt_def.did()).is_empty() {
|
||||
// FIXME(estebank): we could also verify that the arguments being
|
||||
// work for the `enum`, instead of just looking if it takes *any*.
|
||||
err.span_suggestion_verbose(
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// Traits always have `Self` as a generic parameter, which means they will not return early
|
||||
// here and so associated type bindings will be handled regardless of whether there are any
|
||||
// non-`Self` generic parameters.
|
||||
if generics.own_params.is_empty() {
|
||||
if generics.is_own_empty() {
|
||||
return (tcx.mk_args(parent_args), arg_count);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
let def_kind = tcx.def_kind(item_def_id);
|
||||
match def_kind {
|
||||
DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
|
||||
DefKind::Const if tcx.generics_of(item_def_id).own_params.is_empty() => {
|
||||
DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
|
||||
let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|||
debug!("build_constraints_for_item({})", tcx.def_path_str(def_id));
|
||||
|
||||
// Skip items with no generics - there's nothing to infer in them.
|
||||
if tcx.generics_of(def_id).count() == 0 {
|
||||
if tcx.generics_of(def_id).is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ fn crate_variances(tcx: TyCtxt<'_>, (): ()) -> CrateVariancesMap<'_> {
|
|||
|
||||
fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
|
||||
// Skip items with no generics - there's nothing to infer in them.
|
||||
if tcx.generics_of(item_def_id).count() == 0 {
|
||||
if tcx.generics_of(item_def_id).is_empty() {
|
||||
return &[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1454,7 +1454,7 @@ impl<'a> State<'a> {
|
|||
self.word_space(":");
|
||||
}
|
||||
// containing cbox, will be closed by print-block at `}`
|
||||
self.cbox(INDENT_UNIT);
|
||||
self.cbox(0);
|
||||
// head-box, will be closed by print-block after `{`
|
||||
self.ibox(0);
|
||||
self.print_block(blk);
|
||||
|
|
|
|||
|
|
@ -1591,31 +1591,28 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
err.span_label(cause.span, "return type is not `()`");
|
||||
}
|
||||
ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
|
||||
let parent_id = fcx.tcx.parent_hir_id(blk_id);
|
||||
err = self.report_return_mismatched_types(
|
||||
cause,
|
||||
expected,
|
||||
found,
|
||||
coercion_error,
|
||||
fcx,
|
||||
parent_id,
|
||||
blk_id,
|
||||
expression,
|
||||
Some(blk_id),
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals {
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
}
|
||||
}
|
||||
ObligationCauseCode::ReturnValue(id) => {
|
||||
ObligationCauseCode::ReturnValue(return_expr_id) => {
|
||||
err = self.report_return_mismatched_types(
|
||||
cause,
|
||||
expected,
|
||||
found,
|
||||
coercion_error,
|
||||
fcx,
|
||||
id,
|
||||
return_expr_id,
|
||||
expression,
|
||||
None,
|
||||
);
|
||||
if !fcx.tcx.features().unsized_locals {
|
||||
unsized_return = self.is_return_ty_definitely_unsized(fcx);
|
||||
|
|
@ -1809,13 +1806,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
found: Ty<'tcx>,
|
||||
ty_err: TypeError<'tcx>,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
id: hir::HirId,
|
||||
block_or_return_id: hir::HirId,
|
||||
expression: Option<&'tcx hir::Expr<'tcx>>,
|
||||
blk_id: Option<hir::HirId>,
|
||||
) -> Diag<'a> {
|
||||
let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
|
||||
|
||||
let parent_id = fcx.tcx.parent_hir_id(id);
|
||||
let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
|
||||
|
||||
let parent_id = fcx.tcx.parent_hir_id(block_or_return_id);
|
||||
let parent = fcx.tcx.hir_node(parent_id);
|
||||
if let Some(expr) = expression
|
||||
&& let hir::Node::Expr(hir::Expr {
|
||||
|
|
@ -1829,72 +1827,64 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
// Verify that this is a tail expression of a function, otherwise the
|
||||
// label pointing out the cause for the type coercion will be wrong
|
||||
// as prior return coercions would not be relevant (#57664).
|
||||
let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
|
||||
if let Some(expr) = expression
|
||||
&& due_to_block
|
||||
{
|
||||
fcx.suggest_missing_semicolon(&mut err, expr, expected, false);
|
||||
let pointing_at_return_type =
|
||||
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
|
||||
if let (Some(cond_expr), true, false) = (
|
||||
fcx.tcx.hir().get_if_cause(expr.hir_id),
|
||||
expected.is_unit(),
|
||||
pointing_at_return_type,
|
||||
)
|
||||
let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
|
||||
&mut err,
|
||||
expr,
|
||||
expected,
|
||||
found,
|
||||
block_or_return_id,
|
||||
);
|
||||
if let Some(cond_expr) = fcx.tcx.hir().get_if_cause(expr.hir_id)
|
||||
&& expected.is_unit()
|
||||
&& !pointing_at_return_type
|
||||
// If the block is from an external macro or try (`?`) desugaring, then
|
||||
// do not suggest adding a semicolon, because there's nowhere to put it.
|
||||
// See issues #81943 and #87051.
|
||||
&& matches!(
|
||||
cond_expr.span.desugaring_kind(),
|
||||
None | Some(DesugaringKind::WhileLoop)
|
||||
) && !in_external_macro(fcx.tcx.sess, cond_expr.span)
|
||||
&& !matches!(
|
||||
cond_expr.kind,
|
||||
hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
|
||||
)
|
||||
)
|
||||
&& !in_external_macro(fcx.tcx.sess, cond_expr.span)
|
||||
&& !matches!(
|
||||
cond_expr.kind,
|
||||
hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
|
||||
)
|
||||
{
|
||||
err.span_label(cond_expr.span, "expected this to be `()`");
|
||||
if expr.can_have_side_effects() {
|
||||
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
|
||||
}
|
||||
}
|
||||
fcx.get_node_fn_decl(parent)
|
||||
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
|
||||
} else {
|
||||
fcx.get_fn_decl(parent_id)
|
||||
};
|
||||
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
|
||||
if blk_id.is_none() {
|
||||
fcx.suggest_missing_return_type(
|
||||
&mut err,
|
||||
fn_decl,
|
||||
expected,
|
||||
found,
|
||||
can_suggest,
|
||||
fn_id,
|
||||
);
|
||||
}
|
||||
// If this is due to an explicit `return`, suggest adding a return type.
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(parent_id)
|
||||
&& !due_to_block
|
||||
{
|
||||
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
|
||||
}
|
||||
|
||||
let mut parent_id = fcx.tcx.hir().get_parent_item(id).def_id;
|
||||
let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id);
|
||||
// When suggesting return, we need to account for closures and async blocks, not just items.
|
||||
for (_, node) in fcx.tcx.hir().parent_iter(id) {
|
||||
match node {
|
||||
hir::Node::Expr(&hir::Expr {
|
||||
kind: hir::ExprKind::Closure(hir::Closure { def_id, .. }),
|
||||
..
|
||||
}) => {
|
||||
parent_item = node;
|
||||
parent_id = *def_id;
|
||||
break;
|
||||
}
|
||||
hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) {
|
||||
// If this is due to a block, then maybe we forgot a `return`/`break`.
|
||||
if due_to_block
|
||||
&& let Some(expr) = expression
|
||||
&& let Some((parent_fn_decl, parent_id)) = fcx
|
||||
.tcx
|
||||
.hir()
|
||||
.parent_iter(block_or_return_id)
|
||||
.find_map(|(_, node)| Some((node.fn_decl()?, node.associated_body()?.0)))
|
||||
{
|
||||
fcx.suggest_missing_break_or_return_expr(
|
||||
&mut err, expr, fn_decl, expected, found, id, parent_id,
|
||||
&mut err,
|
||||
expr,
|
||||
parent_fn_decl,
|
||||
expected,
|
||||
found,
|
||||
block_or_return_id,
|
||||
parent_id,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1346,6 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if segment.ident.name != kw::Empty {
|
||||
if let Some(err) = self.report_method_error(
|
||||
span,
|
||||
Some(rcvr),
|
||||
rcvr_t,
|
||||
segment.ident,
|
||||
SelfSource::MethodCall(rcvr),
|
||||
|
|
@ -3112,7 +3113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
let true_errors = ocx.select_where_possible();
|
||||
|
||||
// Do a leak check -- we can't really report report a useful error here,
|
||||
// Do a leak check -- we can't really report a useful error here,
|
||||
// but it at least avoids an ICE when the error has to do with higher-ranked
|
||||
// lifetimes.
|
||||
self.leak_check(outer_universe, Some(snapshot))?;
|
||||
|
|
|
|||
|
|
@ -364,41 +364,11 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
};
|
||||
|
||||
let mut fallback_to = |ty| {
|
||||
let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| {
|
||||
let unsafe_infer_vars = compute_unsafe_infer_vars(self.root_ctxt, self.body_id);
|
||||
debug!(?unsafe_infer_vars);
|
||||
unsafe_infer_vars
|
||||
});
|
||||
|
||||
let affected_unsafe_infer_vars =
|
||||
graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
|
||||
.filter_map(|x| unsafe_infer_vars.get(&x).copied())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (hir_id, span, reason) in affected_unsafe_infer_vars {
|
||||
self.tcx.emit_node_span_lint(
|
||||
lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
|
||||
hir_id,
|
||||
span,
|
||||
match reason {
|
||||
UnsafeUseReason::Call => {
|
||||
errors::NeverTypeFallbackFlowingIntoUnsafe::Call
|
||||
}
|
||||
UnsafeUseReason::Method => {
|
||||
errors::NeverTypeFallbackFlowingIntoUnsafe::Method
|
||||
}
|
||||
UnsafeUseReason::Path => {
|
||||
errors::NeverTypeFallbackFlowingIntoUnsafe::Path
|
||||
}
|
||||
UnsafeUseReason::UnionField => {
|
||||
errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField
|
||||
}
|
||||
UnsafeUseReason::Deref => {
|
||||
errors::NeverTypeFallbackFlowingIntoUnsafe::Deref
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
self.lint_never_type_fallback_flowing_into_unsafe_code(
|
||||
&unsafe_infer_vars,
|
||||
&coercion_graph,
|
||||
root_vid,
|
||||
);
|
||||
|
||||
diverging_fallback.insert(diverging_ty, ty);
|
||||
};
|
||||
|
|
@ -464,6 +434,41 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
|
|||
diverging_fallback
|
||||
}
|
||||
|
||||
fn lint_never_type_fallback_flowing_into_unsafe_code(
|
||||
&self,
|
||||
unsafe_infer_vars: &OnceCell<UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>>,
|
||||
coercion_graph: &VecGraph<ty::TyVid, true>,
|
||||
root_vid: ty::TyVid,
|
||||
) {
|
||||
let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| {
|
||||
let unsafe_infer_vars = compute_unsafe_infer_vars(self.root_ctxt, self.body_id);
|
||||
debug!(?unsafe_infer_vars);
|
||||
unsafe_infer_vars
|
||||
});
|
||||
|
||||
let affected_unsafe_infer_vars =
|
||||
graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
|
||||
.filter_map(|x| unsafe_infer_vars.get(&x).copied())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for (hir_id, span, reason) in affected_unsafe_infer_vars {
|
||||
self.tcx.emit_node_span_lint(
|
||||
lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
|
||||
hir_id,
|
||||
span,
|
||||
match reason {
|
||||
UnsafeUseReason::Call => errors::NeverTypeFallbackFlowingIntoUnsafe::Call,
|
||||
UnsafeUseReason::Method => errors::NeverTypeFallbackFlowingIntoUnsafe::Method,
|
||||
UnsafeUseReason::Path => errors::NeverTypeFallbackFlowingIntoUnsafe::Path,
|
||||
UnsafeUseReason::UnionField => {
|
||||
errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField
|
||||
}
|
||||
UnsafeUseReason::Deref => errors::NeverTypeFallbackFlowingIntoUnsafe::Deref,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a graph whose nodes are (unresolved) inference variables and where
|
||||
/// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
|
||||
fn create_coercion_graph(&self) -> VecGraph<ty::TyVid, true> {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use rustc_middle::{bug, span_bug};
|
|||
use rustc_session::lint;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::FieldIdx;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
|
|
@ -834,6 +834,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if item_name.name != kw::Empty {
|
||||
if let Some(e) = self.report_method_error(
|
||||
span,
|
||||
None,
|
||||
ty.normalized,
|
||||
item_name,
|
||||
SelfSource::QPath(qself),
|
||||
|
|
@ -866,76 +867,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure
|
||||
/// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
|
||||
/// This may seem confusing at first, but this is used in diagnostics for `async fn`,
|
||||
/// for example, where most of the type checking actually happens within a nested closure,
|
||||
/// but we often want access to the parent function's signature.
|
||||
///
|
||||
/// Otherwise, return false.
|
||||
pub(crate) fn get_node_fn_decl(
|
||||
&self,
|
||||
node: Node<'tcx>,
|
||||
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
|
||||
match node {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => {
|
||||
// This is less than ideal, it will not suggest a return type span on any
|
||||
// method called `main`, regardless of whether it is actually the entry point,
|
||||
// but it will still present it as the reason for the expected type.
|
||||
Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
|
||||
}
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, &sig.decl, ident, true)),
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, &sig.decl, ident, false)),
|
||||
Node::Expr(&hir::Expr {
|
||||
hir_id,
|
||||
kind:
|
||||
hir::ExprKind::Closure(hir::Closure {
|
||||
kind: hir::ClosureKind::Coroutine(..), ..
|
||||
}),
|
||||
..
|
||||
}) => {
|
||||
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
_ => return None,
|
||||
};
|
||||
Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
|
||||
/// suggestion can be made, `None` otherwise.
|
||||
pub fn get_fn_decl(
|
||||
|
|
@ -944,10 +875,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
|
||||
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
|
||||
// `while` before reaching it, as block tail returns are not available in them.
|
||||
self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
|
||||
let parent = self.tcx.hir_node(blk_id);
|
||||
self.get_node_fn_decl(parent)
|
||||
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
|
||||
self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
|
||||
match self.tcx.hir_node(item_id) {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => {
|
||||
// This is less than ideal, it will not suggest a return type span on any
|
||||
// method called `main`, regardless of whether it is actually the entry point,
|
||||
// but it will still present it as the reason for the expected type.
|
||||
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
|
||||
}
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, sig.decl, true)),
|
||||
// FIXME: Suggestable if this is not a trait implementation
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => Some((owner_id.def_id, sig.decl, false)),
|
||||
Node::Expr(&hir::Expr {
|
||||
hir_id,
|
||||
kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
|
||||
..
|
||||
}) => {
|
||||
match kind {
|
||||
hir::ClosureKind::CoroutineClosure(_) => {
|
||||
// FIXME(async_closures): Implement this.
|
||||
return None;
|
||||
}
|
||||
hir::ClosureKind::Closure => Some((def_id, fn_decl, true)),
|
||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||
_,
|
||||
hir::CoroutineSource::Fn,
|
||||
)) => {
|
||||
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
|
||||
Node::Item(&hir::Item {
|
||||
ident,
|
||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::TraitItem(&hir::TraitItem {
|
||||
ident,
|
||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
Node::ImplItem(&hir::ImplItem {
|
||||
ident,
|
||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||
owner_id,
|
||||
..
|
||||
}) => (ident, sig, owner_id),
|
||||
_ => return None,
|
||||
};
|
||||
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1774,7 +1774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// that highlight errors inline.
|
||||
let mut sp = blk.span;
|
||||
let mut fn_span = None;
|
||||
if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
|
||||
if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) {
|
||||
let ret_sp = decl.output.span();
|
||||
if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
|
||||
// HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
|
||||
|
|
@ -1782,7 +1782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// the span we're aiming at correspond to a `fn` body.
|
||||
if block_sp == blk.span {
|
||||
sp = ret_sp;
|
||||
fn_span = Some(ident.span);
|
||||
fn_span = self.tcx.def_ident_span(fn_def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1897,15 +1897,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
None
|
||||
}
|
||||
|
||||
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
|
||||
pub(crate) fn get_parent_fn_decl(
|
||||
&self,
|
||||
blk_id: HirId,
|
||||
) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
|
||||
let parent = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
|
||||
self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
|
||||
}
|
||||
|
||||
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
|
||||
/// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
|
||||
/// when given code like the following:
|
||||
|
|
|
|||
|
|
@ -800,6 +800,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
can_suggest: bool,
|
||||
fn_id: LocalDefId,
|
||||
) -> bool {
|
||||
// Can't suggest `->` on a block-like coroutine
|
||||
if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Block)) =
|
||||
self.tcx.coroutine_kind(fn_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let found =
|
||||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||
// Only suggest changing the return type for methods that
|
||||
|
|
@ -1909,7 +1916,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let returned = matches!(
|
||||
self.tcx.parent_hir_node(expr.hir_id),
|
||||
hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
|
||||
) || map.get_return_block(expr.hir_id).is_some();
|
||||
) || map.get_fn_id_for_return_block(expr.hir_id).is_some();
|
||||
if returned
|
||||
&& let ty::Adt(e, args_e) = expected.kind()
|
||||
&& let ty::Adt(f, args_f) = found.kind()
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
|
|||
// `foo.bar::<u32>(...)` -- the `Self` type here will be the
|
||||
// type of `foo` (possibly adjusted), but we don't want to
|
||||
// include that. We want just the `[_, u32]` part.
|
||||
if !args.is_empty() && !generics.own_params.is_empty() {
|
||||
if !args.is_empty() && !generics.is_own_empty() {
|
||||
let user_type_annotation = self.probe(|_| {
|
||||
let user_args = UserArgs {
|
||||
args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
|
||||
|
||||
mod confirm;
|
||||
mod prelude2021;
|
||||
mod prelude_edition_lints;
|
||||
pub mod probe;
|
||||
mod suggest;
|
||||
|
||||
|
|
@ -186,7 +186,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let pick =
|
||||
self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
|
||||
|
||||
self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
|
||||
self.lint_edition_dependent_dot_call(
|
||||
self_ty, segment, span, call_expr, self_expr, &pick, args,
|
||||
);
|
||||
|
||||
for &import_id in &pick.import_ids {
|
||||
debug!("used_trait_import: {:?}", import_id);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use crate::{
|
||||
method::probe::{self, Pick},
|
||||
FnCtxt,
|
||||
};
|
||||
use crate::method::probe::{self, Pick};
|
||||
use crate::FnCtxt;
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use hir::HirId;
|
||||
use hir::ItemKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
|
||||
|
|
@ -17,7 +17,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
|||
use std::fmt::Write;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub(super) fn lint_dot_call_from_2018(
|
||||
pub(super) fn lint_edition_dependent_dot_call(
|
||||
&self,
|
||||
self_ty: Ty<'tcx>,
|
||||
segment: &hir::PathSegment<'_>,
|
||||
|
|
@ -32,22 +32,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
segment.ident, self_ty, call_expr, self_expr
|
||||
);
|
||||
|
||||
// Rust 2021 and later is already using the new prelude
|
||||
if span.at_least_rust_2021() {
|
||||
return;
|
||||
}
|
||||
|
||||
let prelude_or_array_lint = match segment.ident.name {
|
||||
let (prelude_or_array_lint, edition) = match segment.ident.name {
|
||||
// `try_into` was added to the prelude in Rust 2021.
|
||||
sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
|
||||
sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
|
||||
// `into_iter` wasn't added to the prelude,
|
||||
// but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
|
||||
// before Rust 2021, which results in the same problem.
|
||||
// It is only a problem for arrays.
|
||||
sym::into_iter if let ty::Array(..) = self_ty.kind() => {
|
||||
// In this case, it wasn't really a prelude addition that was the problem.
|
||||
// Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
|
||||
rustc_lint::ARRAY_INTO_ITER
|
||||
sym::into_iter => {
|
||||
if let ty::Array(..) = self_ty.kind()
|
||||
&& !span.at_least_rust_2021()
|
||||
{
|
||||
// In this case, it wasn't really a prelude addition that was the problem.
|
||||
// Instead, the problem is that the array-into_iter hack will no longer
|
||||
// apply in Rust 2021.
|
||||
(ARRAY_INTO_ITER, "2021")
|
||||
} else if self_ty.is_box()
|
||||
&& self_ty.boxed_ty().is_slice()
|
||||
&& !span.at_least_rust_2024()
|
||||
{
|
||||
// In this case, it wasn't really a prelude addition that was the problem.
|
||||
// Instead, the problem is that the boxed-slice-into_iter hack will no
|
||||
// longer apply in Rust 2024.
|
||||
(BOXED_SLICE_INTO_ITER, "2024")
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
|
@ -81,7 +91,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
prelude_or_array_lint,
|
||||
self_expr.hir_id,
|
||||
self_expr.span,
|
||||
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|
||||
format!(
|
||||
"trait method `{}` will become ambiguous in Rust {edition}",
|
||||
segment.ident.name
|
||||
),
|
||||
|lint| {
|
||||
let sp = self_expr.span;
|
||||
|
||||
|
|
@ -131,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
prelude_or_array_lint,
|
||||
call_expr.hir_id,
|
||||
call_expr.span,
|
||||
format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
|
||||
format!(
|
||||
"trait method `{}` will become ambiguous in Rust {edition}",
|
||||
segment.ident.name
|
||||
),
|
||||
|lint| {
|
||||
let sp = call_expr.span;
|
||||
let trait_name = self.trait_path_or_bare_name(
|
||||
|
|
@ -279,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
if !self_ty_name.contains('<') {
|
||||
if let ty::Adt(def, _) = self_ty.kind() {
|
||||
let generics = self.tcx.generics_of(def.did());
|
||||
if !generics.own_params.is_empty() {
|
||||
if !generics.is_own_empty() {
|
||||
let counts = generics.own_counts();
|
||||
self_ty_name += &format!(
|
||||
"<{}>",
|
||||
|
|
@ -1444,6 +1444,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
return ProbeResult::NoMatch;
|
||||
}
|
||||
}
|
||||
|
||||
// Some trait methods are excluded for boxed slices before 2024.
|
||||
// (`boxed_slice.into_iter()` wants a slice iterator for compatibility.)
|
||||
if self_ty.is_box()
|
||||
&& self_ty.boxed_ty().is_slice()
|
||||
&& !method_name.span.at_least_rust_2024()
|
||||
{
|
||||
let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
|
||||
if trait_def.skip_boxed_slice_during_method_dispatch {
|
||||
return ProbeResult::NoMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let trait_ref = self.instantiate_binder_with_fresh_vars(
|
||||
|
|
@ -1754,7 +1766,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
let generics = self.tcx.generics_of(method);
|
||||
assert_eq!(args.len(), generics.parent_count);
|
||||
|
||||
let xform_fn_sig = if generics.own_params.is_empty() {
|
||||
let xform_fn_sig = if generics.is_own_empty() {
|
||||
fn_sig.instantiate(self.tcx, args)
|
||||
} else {
|
||||
let args = GenericArgs::for_item(self.tcx, method, |param, _| {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
|
|||
use crate::Expectation;
|
||||
use crate::FnCtxt;
|
||||
use core::ops::ControlFlow;
|
||||
use hir::Expr;
|
||||
use rustc_ast::ast::Mutability;
|
||||
use rustc_attr::parse_confusables;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
|
|
@ -19,7 +20,6 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::PatKind::Binding;
|
||||
use rustc_hir::PathSegment;
|
||||
use rustc_hir::{ExprKind, Node, QPath};
|
||||
use rustc_infer::infer::{self, RegionVariableOrigin};
|
||||
|
|
@ -46,7 +46,7 @@ use std::borrow::Cow;
|
|||
|
||||
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
|
||||
use super::{CandidateSource, MethodError, NoMatchData};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
|
|
@ -188,6 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
pub fn report_method_error(
|
||||
&self,
|
||||
span: Span,
|
||||
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
source: SelfSource<'tcx>,
|
||||
|
|
@ -212,6 +213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
MethodError::NoMatch(mut no_match_data) => {
|
||||
return self.report_no_match_method_error(
|
||||
span,
|
||||
rcvr_opt,
|
||||
rcvr_ty,
|
||||
item_name,
|
||||
source,
|
||||
|
|
@ -356,9 +358,197 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err
|
||||
}
|
||||
|
||||
pub fn suggest_use_shadowed_binding_with_method(
|
||||
&self,
|
||||
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
|
||||
method_name: Ident,
|
||||
ty_str_reported: &str,
|
||||
err: &mut Diag<'_>,
|
||||
) {
|
||||
#[derive(Debug)]
|
||||
struct LetStmt {
|
||||
ty_hir_id_opt: Option<hir::HirId>,
|
||||
binding_id: hir::HirId,
|
||||
span: Span,
|
||||
init_hir_id: hir::HirId,
|
||||
}
|
||||
|
||||
// Used for finding suggest binding.
|
||||
// ```rust
|
||||
// earlier binding for suggesting:
|
||||
// let y = vec![1, 2];
|
||||
// now binding:
|
||||
// if let Some(y) = x {
|
||||
// y.push(y);
|
||||
// }
|
||||
// ```
|
||||
struct LetVisitor<'a, 'tcx> {
|
||||
// Error binding which don't have `method_name`.
|
||||
binding_name: Symbol,
|
||||
binding_id: hir::HirId,
|
||||
// Used for check if the suggest binding has `method_name`.
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
call_expr: &'tcx Expr<'tcx>,
|
||||
method_name: Ident,
|
||||
// Suggest the binding which is shallowed.
|
||||
sugg_let: Option<LetStmt>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LetVisitor<'a, 'tcx> {
|
||||
// Check scope of binding.
|
||||
fn is_sub_scope(&self, sub_id: hir::ItemLocalId, super_id: hir::ItemLocalId) -> bool {
|
||||
let scope_tree = self.fcx.tcx.region_scope_tree(self.fcx.body_id);
|
||||
if let Some(sub_var_scope) = scope_tree.var_scope(sub_id)
|
||||
&& let Some(super_var_scope) = scope_tree.var_scope(super_id)
|
||||
&& scope_tree.is_subscope_of(sub_var_scope, super_var_scope)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// Check if an earlier shadowed binding make `the receiver` of a MethodCall has the method.
|
||||
// If it does, record the earlier binding for subsequent notes.
|
||||
fn check_and_add_sugg_binding(&mut self, binding: LetStmt) -> bool {
|
||||
if !self.is_sub_scope(self.binding_id.local_id, binding.binding_id.local_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the earlier shadowed binding'ty and use it to check the method.
|
||||
if let Some(ty_hir_id) = binding.ty_hir_id_opt
|
||||
&& let Some(tyck_ty) = self.fcx.node_ty_opt(ty_hir_id)
|
||||
{
|
||||
if self
|
||||
.fcx
|
||||
.lookup_probe_for_diagnostic(
|
||||
self.method_name,
|
||||
tyck_ty,
|
||||
self.call_expr,
|
||||
ProbeScope::TraitsInScope,
|
||||
None,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
self.sugg_let = Some(binding);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the shadowed binding has an an itializer expression,
|
||||
// use the initializer expression'ty to try to find the method again.
|
||||
// For example like: `let mut x = Vec::new();`,
|
||||
// `Vec::new()` is the itializer expression.
|
||||
if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
|
||||
&& self
|
||||
.fcx
|
||||
.lookup_probe_for_diagnostic(
|
||||
self.method_name,
|
||||
self_ty,
|
||||
self.call_expr,
|
||||
ProbeScope::TraitsInScope,
|
||||
None,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
self.sugg_let = Some(binding);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for LetVisitor<'_, '_> {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
|
||||
if let hir::StmtKind::Let(&hir::LetStmt { pat, ty, init, .. }) = ex.kind
|
||||
&& let hir::PatKind::Binding(_, binding_id, binding_name, ..) = pat.kind
|
||||
&& let Some(init) = init
|
||||
&& binding_name.name == self.binding_name
|
||||
&& binding_id != self.binding_id
|
||||
{
|
||||
if self.check_and_add_sugg_binding(LetStmt {
|
||||
ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None },
|
||||
binding_id: binding_id,
|
||||
span: pat.span,
|
||||
init_hir_id: init.hir_id,
|
||||
}) {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
hir::intravisit::walk_stmt(self, ex)
|
||||
}
|
||||
}
|
||||
|
||||
// Used for find the error binding.
|
||||
// When the visitor reaches this point, all the shadowed bindings
|
||||
// have been found, so the visitor ends.
|
||||
fn visit_pat(&mut self, p: &'v hir::Pat<'v>) -> Self::Result {
|
||||
match p.kind {
|
||||
hir::PatKind::Binding(_, binding_id, binding_name, _) => {
|
||||
if binding_name.name == self.binding_name && binding_id == self.binding_id {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
intravisit::walk_pat(self, p);
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(rcvr) = rcvr_opt
|
||||
&& let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind
|
||||
&& let hir::def::Res::Local(recv_id) = path.res
|
||||
&& let Some(segment) = path.segments.first()
|
||||
{
|
||||
let map = self.infcx.tcx.hir();
|
||||
let body_id = self.tcx.hir().body_owned_by(self.body_id);
|
||||
let body = map.body(body_id);
|
||||
|
||||
if let Node::Expr(call_expr) = self.tcx.parent_hir_node(rcvr.hir_id) {
|
||||
let mut let_visitor = LetVisitor {
|
||||
fcx: self,
|
||||
call_expr,
|
||||
binding_name: segment.ident.name,
|
||||
binding_id: recv_id,
|
||||
method_name,
|
||||
sugg_let: None,
|
||||
};
|
||||
let_visitor.visit_body(body);
|
||||
if let Some(sugg_let) = let_visitor.sugg_let
|
||||
&& let Some(self_ty) = self.node_ty_opt(sugg_let.init_hir_id)
|
||||
{
|
||||
let _sm = self.infcx.tcx.sess.source_map();
|
||||
let rcvr_name = segment.ident.name;
|
||||
let mut span = MultiSpan::from_span(sugg_let.span);
|
||||
span.push_span_label(sugg_let.span,
|
||||
format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));
|
||||
span.push_span_label(
|
||||
self.tcx.hir().span(recv_id),
|
||||
format!(
|
||||
"earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
|
||||
),
|
||||
);
|
||||
err.span_note(
|
||||
span,
|
||||
format!(
|
||||
"there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
|
||||
that has method `{method_name}` available"
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn report_no_match_method_error(
|
||||
&self,
|
||||
mut span: Span,
|
||||
rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
source: SelfSource<'tcx>,
|
||||
|
|
@ -451,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
|
||||
self.suggest_missing_writer(rcvr_ty, rcvr_expr)
|
||||
} else {
|
||||
tcx.dcx().create_err(NoAssociatedItem {
|
||||
let mut err = tcx.dcx().create_err(NoAssociatedItem {
|
||||
span,
|
||||
item_kind,
|
||||
item_name,
|
||||
|
|
@ -461,9 +651,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
} else {
|
||||
rcvr_ty.prefix_string(self.tcx)
|
||||
},
|
||||
ty_str: ty_str_reported,
|
||||
ty_str: ty_str_reported.clone(),
|
||||
trait_missing_method,
|
||||
})
|
||||
});
|
||||
|
||||
if is_method {
|
||||
self.suggest_use_shadowed_binding_with_method(
|
||||
rcvr_opt,
|
||||
item_name,
|
||||
&ty_str_reported,
|
||||
&mut err,
|
||||
);
|
||||
}
|
||||
|
||||
err
|
||||
};
|
||||
if tcx.sess.source_map().is_multiline(sugg_span) {
|
||||
err.span_label(sugg_span.with_hi(span.lo()), "");
|
||||
|
|
@ -2240,7 +2441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
|
||||
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
|
||||
if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
|
||||
&& let Binding(_, _, ident, ..) = pat.kind
|
||||
&& let hir::PatKind::Binding(_, _, ident, ..) = pat.kind
|
||||
&& ident.name == self.ident_name
|
||||
{
|
||||
ControlFlow::Break(init)
|
||||
|
|
|
|||
|
|
@ -164,7 +164,10 @@ infer_label_bad = {$bad_kind ->
|
|||
infer_lf_bound_not_satisfied = lifetime bound not satisfied
|
||||
infer_lifetime_mismatch = lifetime mismatch
|
||||
|
||||
infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
|
||||
infer_lifetime_param_suggestion = consider {$is_reuse ->
|
||||
[true] reusing
|
||||
*[false] introducing
|
||||
} a named lifetime parameter{$is_impl ->
|
||||
[true] {" "}and update trait if needed
|
||||
*[false] {""}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use hir::GenericParamKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{
|
||||
codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg,
|
||||
MultiSpan, SubdiagMessageOp, Subdiagnostic,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::{walk_ty, Visitor};
|
||||
use rustc_hir::FnRetTy;
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
|
||||
|
|
@ -355,31 +357,33 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
_f: &F,
|
||||
) {
|
||||
let mut mk_suggestion = || {
|
||||
let (
|
||||
hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
|
||||
hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
|
||||
) = (self.ty_sub, self.ty_sup)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
|
||||
let is_impl = matches!(&node, hir::Node::ImplItem(_));
|
||||
let generics = match node {
|
||||
let (generics, parent_generics) = match node {
|
||||
hir::Node::Item(&hir::Item {
|
||||
kind: hir::ItemKind::Fn(_, ref generics, ..),
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
|
||||
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
|
||||
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
|
||||
generics,
|
||||
match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
|
||||
{
|
||||
hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Trait(_, _, ref generics, ..),
|
||||
..
|
||||
})
|
||||
| hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
|
||||
..
|
||||
}) => Some(generics),
|
||||
_ => None,
|
||||
},
|
||||
),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
|
|
@ -390,24 +394,112 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
.map(|p| p.name.ident().name)
|
||||
.find(|i| *i != kw::UnderscoreLifetime);
|
||||
let introduce_new = suggestion_param_name.is_none();
|
||||
|
||||
let mut default = "'a".to_string();
|
||||
if let Some(parent_generics) = parent_generics {
|
||||
let used: FxHashSet<_> = parent_generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
|
||||
.map(|p| p.name.ident().name)
|
||||
.filter(|i| *i != kw::UnderscoreLifetime)
|
||||
.map(|l| l.to_string())
|
||||
.collect();
|
||||
if let Some(lt) =
|
||||
('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
|
||||
{
|
||||
// We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
|
||||
// `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
|
||||
// likely to be an over-constraining lifetime requirement, so we always add a
|
||||
// lifetime to the `fn`.
|
||||
default = lt;
|
||||
}
|
||||
}
|
||||
let suggestion_param_name =
|
||||
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
|
||||
suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
|
||||
|
||||
debug!(?lifetime_sup.ident.span);
|
||||
debug!(?lifetime_sub.ident.span);
|
||||
let make_suggestion = |ident: Ident| {
|
||||
let sugg = if ident.name == kw::Empty {
|
||||
format!("{suggestion_param_name}, ")
|
||||
} else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
|
||||
format!("{suggestion_param_name} ")
|
||||
} else {
|
||||
suggestion_param_name.clone()
|
||||
};
|
||||
(ident.span, sugg)
|
||||
struct ImplicitLifetimeFinder {
|
||||
suggestions: Vec<(Span, String)>,
|
||||
suggestion_param_name: String,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
|
||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||
let make_suggestion = |ident: Ident| {
|
||||
if ident.name == kw::Empty && ident.span.is_empty() {
|
||||
format!("{}, ", self.suggestion_param_name)
|
||||
} else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
|
||||
format!("{} ", self.suggestion_param_name)
|
||||
} else {
|
||||
self.suggestion_param_name.clone()
|
||||
}
|
||||
};
|
||||
match ty.kind {
|
||||
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
|
||||
for segment in path.segments {
|
||||
if let Some(args) = segment.args {
|
||||
if args.args.iter().all(|arg| {
|
||||
matches!(
|
||||
arg,
|
||||
hir::GenericArg::Lifetime(lifetime)
|
||||
if lifetime.ident.name == kw::Empty
|
||||
)
|
||||
}) {
|
||||
self.suggestions.push((
|
||||
segment.ident.span.shrink_to_hi(),
|
||||
format!(
|
||||
"<{}>",
|
||||
args.args
|
||||
.iter()
|
||||
.map(|_| self.suggestion_param_name.clone())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
));
|
||||
} else {
|
||||
for arg in args.args {
|
||||
if let hir::GenericArg::Lifetime(lifetime) = arg
|
||||
&& lifetime.is_anonymous()
|
||||
{
|
||||
self.suggestions.push((
|
||||
lifetime.ident.span,
|
||||
make_suggestion(lifetime.ident),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
|
||||
self.suggestions
|
||||
.push((lifetime.ident.span, make_suggestion(lifetime.ident)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
walk_ty(self, ty);
|
||||
}
|
||||
}
|
||||
let mut visitor = ImplicitLifetimeFinder {
|
||||
suggestions: vec![],
|
||||
suggestion_param_name: suggestion_param_name.clone(),
|
||||
};
|
||||
let mut suggestions =
|
||||
vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
|
||||
|
||||
if let Some(fn_decl) = node.fn_decl()
|
||||
&& let hir::FnRetTy::Return(ty) = fn_decl.output
|
||||
{
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
if visitor.suggestions.is_empty() {
|
||||
// Do not suggest constraining the `&self` param, but rather the return type.
|
||||
// If that is wrong (because it is not sufficient), a follow up error will tell the
|
||||
// user to fix it. This way we lower the chances of *over* constraining, but still
|
||||
// get the cake of "correctly" contrained in two steps.
|
||||
visitor.visit_ty(self.ty_sup);
|
||||
}
|
||||
visitor.visit_ty(self.ty_sub);
|
||||
if visitor.suggestions.is_empty() {
|
||||
return false;
|
||||
}
|
||||
if introduce_new {
|
||||
let new_param_suggestion = if let Some(first) =
|
||||
generics.params.iter().find(|p| !p.name.ident().span.is_empty())
|
||||
|
|
@ -417,15 +509,16 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
(generics.span, format!("<{suggestion_param_name}>"))
|
||||
};
|
||||
|
||||
suggestions.push(new_param_suggestion);
|
||||
visitor.suggestions.push(new_param_suggestion);
|
||||
}
|
||||
|
||||
diag.multipart_suggestion(
|
||||
diag.multipart_suggestion_verbose(
|
||||
fluent::infer_lifetime_param_suggestion,
|
||||
suggestions,
|
||||
visitor.suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.arg("is_impl", is_impl);
|
||||
diag.arg("is_reuse", !introduce_new);
|
||||
|
||||
true
|
||||
};
|
||||
if mk_suggestion() && self.add_note {
|
||||
|
|
|
|||
|
|
@ -369,34 +369,44 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, vid: TyVid) -> TyVid {
|
||||
self.root_var(vid)
|
||||
}
|
||||
|
||||
fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> {
|
||||
self.probe_ty_var(vid).ok()
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
|
||||
let re = self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.tcx, vid);
|
||||
if *re == ty::ReVar(vid) { None } else { Some(re) }
|
||||
}
|
||||
|
||||
fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
|
||||
self.root_const_var(vid)
|
||||
}
|
||||
|
||||
fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
|
||||
self.probe_const_var(vid).ok()
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
|
||||
match self.probe_ty_var(vid) {
|
||||
Ok(ty) => ty,
|
||||
Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_int_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
|
||||
match self.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
|
||||
match self.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => {
|
||||
ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See the `error_reporting` module for more details.
|
||||
|
|
|
|||
|
|
@ -173,84 +173,3 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EAGER RESOLUTION
|
||||
|
||||
/// Resolves ty, region, and const vars to their inferred values or their root vars.
|
||||
pub struct EagerResolver<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EagerResolver<'a, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
EagerResolver { infcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match *t.kind() {
|
||||
ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
|
||||
Ok(t) => t.fold_with(self),
|
||||
Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
|
||||
},
|
||||
ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
|
||||
ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
|
||||
_ => {
|
||||
if t.has_infer() {
|
||||
t.super_fold_with(self)
|
||||
} else {
|
||||
t
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
match *r {
|
||||
ty::ReVar(vid) => self
|
||||
.infcx
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.infcx.tcx, vid),
|
||||
_ => r,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
match c.kind() {
|
||||
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
|
||||
// FIXME: we need to fold the ty too, I think.
|
||||
match self.infcx.probe_const_var(vid) {
|
||||
Ok(c) => c.fold_with(self),
|
||||
Err(_) => {
|
||||
ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
|
||||
debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
|
||||
self.infcx.probe_effect_var(vid).unwrap_or_else(|| {
|
||||
ty::Const::new_infer(
|
||||
self.infcx.tcx,
|
||||
ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
|
||||
self.infcx.tcx.types.bool,
|
||||
)
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
if c.has_infer() {
|
||||
c.super_fold_with(self)
|
||||
} else {
|
||||
c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,6 +389,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
|
|||
let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
|
||||
|
||||
util::run_in_thread_pool_with_globals(
|
||||
&early_dcx,
|
||||
config.opts.edition,
|
||||
config.opts.unstable_opts.threads,
|
||||
SourceMapInputs { file_loader, path_mapping, hash_kind },
|
||||
|
|
|
|||
|
|
@ -51,20 +51,38 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
|
|||
pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
|
||||
pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
|
||||
|
||||
fn init_stack_size() -> usize {
|
||||
fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize {
|
||||
// Obey the environment setting or default
|
||||
*STACK_SIZE.get_or_init(|| {
|
||||
env::var_os("RUST_MIN_STACK")
|
||||
.map(|os_str| os_str.to_string_lossy().into_owned())
|
||||
// ignore if it is set to nothing
|
||||
.filter(|s| s.trim() != "")
|
||||
.map(|s| s.trim().parse::<usize>().unwrap())
|
||||
.as_ref()
|
||||
.map(|os_str| os_str.to_string_lossy())
|
||||
// if someone finds out `export RUST_MIN_STACK=640000` isn't enough stack
|
||||
// they might try to "unset" it by running `RUST_MIN_STACK= rustc code.rs`
|
||||
// this is wrong, but std would nonetheless "do what they mean", so let's do likewise
|
||||
.filter(|s| !s.trim().is_empty())
|
||||
// rustc is a batch program, so error early on inputs which are unlikely to be intended
|
||||
// so no one thinks we parsed them setting `RUST_MIN_STACK="64 megabytes"`
|
||||
// FIXME: we could accept `RUST_MIN_STACK=64MB`, perhaps?
|
||||
.map(|s| {
|
||||
let s = s.trim();
|
||||
// FIXME(workingjubilee): add proper diagnostics when we factor out "pre-run" setup
|
||||
#[allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)]
|
||||
s.parse::<usize>().unwrap_or_else(|_| {
|
||||
let mut err = early_dcx.early_struct_fatal(format!(
|
||||
r#"`RUST_MIN_STACK` should be a number of bytes, but was "{s}""#,
|
||||
));
|
||||
err.note("you can also unset `RUST_MIN_STACK` to use the default stack size");
|
||||
err.emit()
|
||||
})
|
||||
})
|
||||
// otherwise pick a consistent default
|
||||
.unwrap_or(DEFAULT_STACK_SIZE)
|
||||
})
|
||||
}
|
||||
|
||||
fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||
thread_stack_size: usize,
|
||||
edition: Edition,
|
||||
sm_inputs: SourceMapInputs,
|
||||
f: F,
|
||||
|
|
@ -75,7 +93,7 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
|||
// the parallel compiler, in particular to ensure there is no accidental
|
||||
// sharing of data between the main thread and the compilation thread
|
||||
// (which might cause problems for the parallel compiler).
|
||||
let builder = thread::Builder::new().name("rustc".to_string()).stack_size(init_stack_size());
|
||||
let builder = thread::Builder::new().name("rustc".to_string()).stack_size(thread_stack_size);
|
||||
|
||||
// We build the session globals and run `f` on the spawned thread, because
|
||||
// `SessionGlobals` does not impl `Send` in the non-parallel compiler.
|
||||
|
|
@ -100,16 +118,19 @@ fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
|||
|
||||
#[cfg(not(parallel_compiler))]
|
||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||
thread_builder_diag: &EarlyDiagCtxt,
|
||||
edition: Edition,
|
||||
_threads: usize,
|
||||
sm_inputs: SourceMapInputs,
|
||||
f: F,
|
||||
) -> R {
|
||||
run_in_thread_with_globals(edition, sm_inputs, f)
|
||||
let thread_stack_size = init_stack_size(thread_builder_diag);
|
||||
run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, f)
|
||||
}
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||
thread_builder_diag: &EarlyDiagCtxt,
|
||||
edition: Edition,
|
||||
threads: usize,
|
||||
sm_inputs: SourceMapInputs,
|
||||
|
|
@ -121,10 +142,12 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
|
|||
use rustc_query_system::query::{break_query_cycles, QueryContext};
|
||||
use std::process;
|
||||
|
||||
let thread_stack_size = init_stack_size(thread_builder_diag);
|
||||
|
||||
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
||||
|
||||
if !sync::is_dyn_thread_safe() {
|
||||
return run_in_thread_with_globals(edition, sm_inputs, |current_gcx| {
|
||||
return run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, |current_gcx| {
|
||||
// Register the thread for use with the `WorkerLocal` type.
|
||||
registry.register();
|
||||
|
||||
|
|
@ -167,7 +190,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
|
|||
})
|
||||
.unwrap();
|
||||
})
|
||||
.stack_size(init_stack_size());
|
||||
.stack_size(thread_stack_size);
|
||||
|
||||
// We create the session globals on the main thread, then create the thread
|
||||
// pool. Upon creation, each worker thread created gets a copy of the
|
||||
|
|
@ -376,31 +399,17 @@ pub(crate) fn check_attr_crate_type(
|
|||
|
||||
if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() {
|
||||
let span = spanned.span;
|
||||
let lev_candidate = find_best_match_for_name(
|
||||
let candidate = find_best_match_for_name(
|
||||
&CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
|
||||
n,
|
||||
None,
|
||||
);
|
||||
if let Some(candidate) = lev_candidate {
|
||||
lint_buffer.buffer_lint_with_diagnostic(
|
||||
lint::builtin::UNKNOWN_CRATE_TYPES,
|
||||
ast::CRATE_NODE_ID,
|
||||
span,
|
||||
"invalid `crate_type` value",
|
||||
BuiltinLintDiag::UnknownCrateTypes(
|
||||
span,
|
||||
"did you mean".to_string(),
|
||||
format!("\"{candidate}\""),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
lint_buffer.buffer_lint(
|
||||
lint::builtin::UNKNOWN_CRATE_TYPES,
|
||||
ast::CRATE_NODE_ID,
|
||||
span,
|
||||
"invalid `crate_type` value",
|
||||
);
|
||||
}
|
||||
lint_buffer.buffer_lint(
|
||||
lint::builtin::UNKNOWN_CRATE_TYPES,
|
||||
ast::CRATE_NODE_ID,
|
||||
span,
|
||||
BuiltinLintDiag::UnknownCrateTypes { span, candidate },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// This is here mainly to check for using a macro, such as
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
lint_abs_path_with_module = absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
|
||||
.suggestion = use `crate`
|
||||
|
||||
lint_ambiguous_glob_reexport = ambiguous glob re-exports
|
||||
.label_first_reexport = the name `{$name}` in the {$namespace} namespace is first re-exported here
|
||||
.label_duplicate_reexport = but the name `{$name}` in the {$namespace} namespace is also re-exported here
|
||||
|
||||
lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
|
||||
.addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
|
||||
.addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
||||
|
||||
lint_array_into_iter =
|
||||
this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021
|
||||
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
.remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
|
||||
.use_explicit_into_iter_suggestion =
|
||||
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
lint_associated_const_elided_lifetime = {$elided ->
|
||||
[true] `&` without an explicit lifetime name cannot be used here
|
||||
*[false] `'_` cannot be used here
|
||||
}
|
||||
.suggestion = use the `'static` lifetime
|
||||
|
||||
lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
|
||||
.note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
|
||||
|
|
@ -26,10 +32,19 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order
|
|||
lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
|
||||
.help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
|
||||
|
||||
lint_avoid_att_syntax =
|
||||
avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
|
||||
|
||||
lint_avoid_intel_syntax =
|
||||
avoid using `.intel_syntax`, Intel syntax is the default
|
||||
|
||||
lint_bad_attribute_argument = bad attribute argument
|
||||
|
||||
lint_bad_opt_access = {$msg}
|
||||
|
||||
lint_break_with_label_and_loop = this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression
|
||||
.suggestion = wrap this expression in parentheses
|
||||
|
||||
lint_builtin_allow_internal_unsafe =
|
||||
`allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
|
||||
|
||||
|
|
@ -37,6 +52,8 @@ lint_builtin_anonymous_params = anonymous parameters are deprecated and will be
|
|||
.suggestion = try naming the parameter or explicitly ignoring it
|
||||
|
||||
lint_builtin_asm_labels = avoid using named labels in inline assembly
|
||||
.help = only local labels of the form `<number>:` should be used in inline asm
|
||||
.note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
|
||||
|
||||
lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
|
||||
|
||||
|
|
@ -161,6 +178,12 @@ lint_builtin_unused_doc_comment = unused doc comment
|
|||
lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
|
||||
.suggestion = use `loop`
|
||||
|
||||
lint_byte_slice_in_packed_struct_with_derive = {$ty} slice in a packed struct that derives a built-in trait
|
||||
.help = consider implementing the trait by hand, or remove the `packed` attribute
|
||||
|
||||
lint_cfg_attr_no_attributes =
|
||||
`#[cfg_attr]` does not expand to any attributes
|
||||
|
||||
lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
|
||||
|
||||
lint_command_line_source = `forbid` lint level was set on command line
|
||||
|
|
@ -169,12 +192,20 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
|
|||
.current_use = this identifier can be confused with `{$existing_sym}`
|
||||
.other_use = other identifier used here
|
||||
|
||||
lint_crate_name_in_cfg_attr_deprecated =
|
||||
`crate_name` within an `#![cfg_attr]` attribute is deprecated
|
||||
|
||||
lint_crate_type_in_cfg_attr_deprecated =
|
||||
`crate_type` within an `#![cfg_attr]` attribute is deprecated
|
||||
|
||||
lint_cstring_ptr = getting the inner pointer of a temporary `CString`
|
||||
.as_ptr_label = this pointer will be invalid
|
||||
.unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
|
||||
.note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
|
||||
.help = for more information, see https://doc.rust-lang.org/reference/destructors.html
|
||||
|
||||
lint_custom_inner_attribute_unstable = custom inner attributes are unstable
|
||||
|
||||
lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
|
||||
.note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
|
||||
|
||||
|
|
@ -185,6 +216,11 @@ lint_deprecated_lint_name =
|
|||
.suggestion = change it to
|
||||
.help = change it to {$replace}
|
||||
|
||||
lint_deprecated_where_clause_location = where clause not allowed here
|
||||
.note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
|
||||
.suggestion_move_to_end = move it to the end of the type declaration
|
||||
.suggestion_remove_where = remove this `where`
|
||||
|
||||
lint_diag_out_of_impl =
|
||||
diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
|
||||
|
||||
|
|
@ -202,6 +238,11 @@ lint_dropping_references = calls to `std::mem::drop` with a reference instead of
|
|||
.label = argument has type `{$arg_ty}`
|
||||
.note = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_duplicate_macro_attribute =
|
||||
duplicated attribute
|
||||
|
||||
lint_duplicate_matcher_binding = duplicate matcher binding
|
||||
|
||||
lint_enum_intrinsics_mem_discriminant =
|
||||
the return value of `mem::discriminant` is unspecified when called with a non-enum type
|
||||
.note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum.
|
||||
|
|
@ -214,6 +255,13 @@ lint_expectation = this lint expectation is unfulfilled
|
|||
.note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
|
||||
.rationale = {$rationale}
|
||||
|
||||
lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition
|
||||
.suggestion = convert it to a `use`
|
||||
|
||||
lint_extern_without_abi = extern declarations without an explicit ABI are deprecated
|
||||
.label = ABI should be specified here
|
||||
.help = the default ABI is {$default_abi}
|
||||
|
||||
lint_for_loops_over_fallibles =
|
||||
for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
|
||||
.suggestion = consider using `if let` to clear intent
|
||||
|
|
@ -228,6 +276,12 @@ lint_forgetting_references = calls to `std::mem::forget` with a reference instea
|
|||
.label = argument has type `{$arg_ty}`
|
||||
.note = use `let _ = ...` to ignore the expression or result
|
||||
|
||||
lint_hidden_glob_reexport = private item shadows public glob re-export
|
||||
.note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here
|
||||
.note_private_item = but the private item here shadows it
|
||||
|
||||
lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated
|
||||
|
||||
lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
|
||||
.label = this {$label} contains {$count ->
|
||||
[one] an invisible
|
||||
|
|
@ -269,6 +323,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
|
|||
|
||||
lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
|
||||
|
||||
lint_ill_formed_attribute_input = {$num_suggestions ->
|
||||
[1] attribute must be of the form {$suggestions}
|
||||
*[other] valid forms for the attribute are {$suggestions}
|
||||
}
|
||||
|
||||
lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than possibly intended in edition 2024
|
||||
.note = specifically, {$num_captured ->
|
||||
[one] this lifetime is
|
||||
|
|
@ -339,6 +398,14 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
|
|||
lint_improper_ctypes_union_layout_reason = this union has unspecified layout
|
||||
lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
|
||||
|
||||
lint_incomplete_include =
|
||||
include macro expected single expression in source
|
||||
|
||||
lint_inner_macro_attribute_unstable = inner macro attributes are unstable
|
||||
|
||||
lint_invalid_crate_type_value = invalid `crate_type` value
|
||||
.suggestion = did you mean
|
||||
|
||||
# FIXME: we should ordinalize $valid_up_to when we add support for doing so
|
||||
lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error
|
||||
.label = the literal was valid UTF-8 up to the {$valid_up_to} bytes
|
||||
|
|
@ -367,9 +434,22 @@ lint_invalid_reference_casting_note_book = for more information, visit <https://
|
|||
|
||||
lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
|
||||
|
||||
lint_legacy_derive_helpers = derive helper attribute is used before it is introduced
|
||||
.label = the attribute is introduced here
|
||||
|
||||
lint_lintpass_by_hand = implementing `LintPass` by hand
|
||||
.help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
|
||||
|
||||
lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
|
||||
.note = the macro is defined here
|
||||
|
||||
lint_macro_is_private = macro `{$ident}` is private
|
||||
|
||||
lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used
|
||||
|
||||
lint_macro_use_deprecated =
|
||||
deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
|
||||
|
||||
lint_malformed_attribute = malformed lint attribute input
|
||||
|
||||
lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
|
||||
|
|
@ -379,6 +459,12 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
|
|||
.map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
|
||||
.suggestion = you might have meant to use `Iterator::for_each`
|
||||
|
||||
lint_metavariable_still_repeating = variable '{$name}' is still repeating at this depth
|
||||
|
||||
lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
|
||||
|
||||
lint_missing_fragment_specifier = missing fragment specifier
|
||||
|
||||
lint_mixed_script_confusables =
|
||||
the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
|
||||
.includes_note = the usage includes {$includes}
|
||||
|
|
@ -386,6 +472,11 @@ lint_mixed_script_confusables =
|
|||
|
||||
lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
|
||||
|
||||
lint_named_argument_used_positionally = named argument `{$named_arg_name}` is not used by name
|
||||
.label_named_arg = this named argument is referred to by position in formatting string
|
||||
.label_position_arg = this formatting argument uses named argument `{$named_arg_name}` by position
|
||||
.suggestion = use the named argument by name to avoid ambiguity
|
||||
|
||||
lint_node_source = `forbid` level set here
|
||||
.note = {$reason}
|
||||
|
||||
|
|
@ -497,6 +588,9 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
|
|||
|
||||
lint_opaque_hidden_inferred_bound_sugg = add this bound
|
||||
|
||||
lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
|
||||
.suggestion = use pat_param to preserve semantics
|
||||
|
||||
lint_overflowing_bin_hex = literal out of range for `{$ty}`
|
||||
.negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
|
||||
.negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}`
|
||||
|
|
@ -526,6 +620,21 @@ lint_path_statement_drop = path statement drops value
|
|||
|
||||
lint_path_statement_no_effect = path statement with no effect
|
||||
|
||||
lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies
|
||||
.label = pattern not allowed in function without body
|
||||
|
||||
lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations
|
||||
.label = pattern not allowed in foreign function
|
||||
|
||||
lint_private_extern_crate_reexport =
|
||||
extern crate `{$ident}` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
|
||||
|
||||
lint_proc_macro_back_compat = using an old version of `{$crate_name}`
|
||||
.note = older versions of the `{$crate_name}` crate will stop compiling in future versions of Rust; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
|
||||
|
||||
lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope
|
||||
.label = names from parent modules are not accessible without an explicit import
|
||||
|
||||
lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false
|
||||
.help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
|
||||
.label = expression has type `{$orig_ty}`
|
||||
|
|
@ -547,6 +656,16 @@ lint_reason_must_be_string_literal = reason must be a string literal
|
|||
|
||||
lint_reason_must_come_last = reason in lint attribute must come last
|
||||
|
||||
lint_redundant_import = the item `{$ident}` is imported redundantly
|
||||
.label_imported_here = the item `{ident}` is already imported here
|
||||
.label_defined_here = the item `{ident}` is already defined here
|
||||
.label_imported_prelude = the item `{ident}` is already imported by the extern prelude
|
||||
.label_defined_prelude = the item `{ident}` is already defined by the extern prelude
|
||||
|
||||
lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough
|
||||
.note = the most public imported item is `{$max_vis}`
|
||||
.help = reduce the glob import's visibility or increase visibility of imported items
|
||||
|
||||
lint_redundant_semicolons =
|
||||
unnecessary trailing {$multiple ->
|
||||
[true] semicolons
|
||||
|
|
@ -557,6 +676,8 @@ lint_redundant_semicolons =
|
|||
*[false] this semicolon
|
||||
}
|
||||
|
||||
lint_remove_mut_from_pattern = remove `mut` from the parameter
|
||||
|
||||
lint_removed_lint = lint `{$name}` has been removed: {$reason}
|
||||
|
||||
lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
|
||||
|
|
@ -565,6 +686,22 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
|
|||
|
||||
lint_requested_level = requested on the command line with `{$level} {$lint_name}`
|
||||
|
||||
lint_reserved_prefix = prefix `{$prefix}` is unknown
|
||||
.label = unknown prefix
|
||||
.suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021
|
||||
|
||||
lint_shadowed_into_iter =
|
||||
this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition}
|
||||
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
|
||||
.remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
|
||||
.use_explicit_into_iter_suggestion =
|
||||
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
|
||||
|
||||
lint_single_use_lifetime = lifetime parameter `{$ident}` only used once
|
||||
.label_param = this lifetime...
|
||||
.label_use = ...is used only here
|
||||
.suggestion = elide the single-use lifetime
|
||||
|
||||
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
|
||||
|
||||
lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
|
||||
|
|
@ -578,6 +715,10 @@ lint_suspicious_double_ref_clone =
|
|||
lint_suspicious_double_ref_deref =
|
||||
using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
|
||||
|
||||
lint_trailing_semi_macro = trailing semicolon in macro used in expression position
|
||||
.note1 = macro invocations at the end of a block are treated as expressions
|
||||
.note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`
|
||||
|
||||
lint_ty_qualified = usage of qualified `ty::{$ty}`
|
||||
.suggestion = try importing it and using it unqualified
|
||||
|
||||
|
|
@ -591,12 +732,64 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual
|
|||
.label = argument has type `{$arg_ty}`
|
||||
.suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
|
||||
|
||||
lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs`
|
||||
lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
|
||||
lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
|
||||
lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}`
|
||||
lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml`
|
||||
lint_unexpected_cfg_doc_cargo = see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
|
||||
lint_unexpected_cfg_doc_rustc = see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
|
||||
|
||||
lint_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}`
|
||||
lint_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more ->
|
||||
[0] {""}
|
||||
*[other] {" "}and {$and_more} more
|
||||
}
|
||||
lint_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities}
|
||||
lint_unexpected_cfg_name_similar_name = there is a config with a similar name
|
||||
lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values
|
||||
lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value
|
||||
lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value
|
||||
lint_unexpected_cfg_name_with_similar_value = found config with similar value
|
||||
|
||||
lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value ->
|
||||
[true] `{$value}`
|
||||
*[false] (none)
|
||||
}
|
||||
lint_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml`
|
||||
lint_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility ->
|
||||
[true] {"(none), "}
|
||||
*[false] {""}
|
||||
}{$possibilities}{$and_more ->
|
||||
[0] {""}
|
||||
*[other] {" "}and {$and_more} more
|
||||
}
|
||||
lint_unexpected_cfg_value_no_expected_value = no expected value for `{$name}`
|
||||
lint_unexpected_cfg_value_no_expected_values = no expected values for `{$name}`
|
||||
lint_unexpected_cfg_value_remove_condition = remove the condition
|
||||
lint_unexpected_cfg_value_remove_value = remove the value
|
||||
lint_unexpected_cfg_value_similar_name = there is a expected value with a similar name
|
||||
lint_unexpected_cfg_value_specify_value = specify a config value
|
||||
|
||||
lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
|
||||
.label = this function will not propagate the caller location
|
||||
|
||||
lint_unicode_text_flow = unicode codepoint changing visible direction of text present in comment
|
||||
.label = {$num_codepoints ->
|
||||
[1] this comment contains an invisible unicode text flow control codepoint
|
||||
*[other] this comment contains invisible unicode text flow control codepoints
|
||||
}
|
||||
.note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
|
||||
.suggestion = if their presence wasn't intentional, you can remove them
|
||||
.label_comment_char = {$c_debug}
|
||||
|
||||
|
||||
lint_unit_bindings = binding has unit type `()`
|
||||
.label = this pattern is inferred to be the unit type `()`
|
||||
|
||||
lint_unknown_diagnostic_attribute = unknown diagnostic attribute
|
||||
lint_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists
|
||||
|
||||
lint_unknown_gated_lint =
|
||||
unknown lint: `{$name}`
|
||||
.note = the `{$name}` lint is unstable
|
||||
|
|
@ -612,9 +805,16 @@ lint_unknown_lint =
|
|||
*[false] did you mean: `{$replace}`
|
||||
}
|
||||
|
||||
lint_unknown_macro_variable = unknown macro variable `{$name}`
|
||||
|
||||
lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
|
||||
.help = add `#![register_tool({$tool_name})]` to the crate root
|
||||
|
||||
lint_unnameable_test_items = cannot test inner items
|
||||
|
||||
lint_unnecessary_qualification = unnecessary qualification
|
||||
.suggestion = remove the unnecessary path segments
|
||||
|
||||
lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
|
||||
|
||||
lint_untranslatable_diag = diagnostics should be created using translatable messages
|
||||
|
|
@ -622,6 +822,9 @@ lint_untranslatable_diag = diagnostics should be created using translatable mess
|
|||
lint_unused_allocation = unnecessary allocation, use `&` instead
|
||||
lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
|
||||
|
||||
lint_unused_builtin_attribute = unused attribute `{$attr_name}`
|
||||
.note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`
|
||||
|
||||
lint_unused_closure =
|
||||
unused {$pre}{$count ->
|
||||
[one] closure
|
||||
|
|
@ -638,14 +841,43 @@ lint_unused_coroutine =
|
|||
}{$post} that must be used
|
||||
.note = coroutines are lazy and do nothing unless resumed
|
||||
|
||||
lint_unused_crate_dependency = external crate `{$extern_crate}` unused in `{$local_crate}`: remove the dependency or add `use {$extern_crate} as _;`
|
||||
|
||||
lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
|
||||
.suggestion = use `let _ = ...` to ignore the resulting value
|
||||
|
||||
lint_unused_delim = unnecessary {$delim} around {$item}
|
||||
.suggestion = remove these {$delim}
|
||||
|
||||
lint_unused_doc_comment = unused doc comment
|
||||
.label = rustdoc does not generate documentation for macro invocations
|
||||
.help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion
|
||||
|
||||
lint_unused_extern_crate = unused extern crate
|
||||
.suggestion = remove it
|
||||
|
||||
lint_unused_import_braces = braces around {$node} is unnecessary
|
||||
|
||||
lint_unused_imports = {$num_snippets ->
|
||||
[one] unused import: {$span_snippets}
|
||||
*[other] unused imports: {$span_snippets}
|
||||
}
|
||||
.suggestion_remove_whole_use = remove the whole `use` item
|
||||
.suggestion_remove_imports = {$num_to_remove ->
|
||||
[one] remove the unused import
|
||||
*[other] remove the unused imports
|
||||
}
|
||||
.help = if this is a test module, consider adding a `#[cfg(test)]` to the containing module
|
||||
|
||||
lint_unused_label = unused label
|
||||
|
||||
lint_unused_lifetime = lifetime parameter `{$ident}` never used
|
||||
.suggestion = elide the unused lifetime
|
||||
|
||||
lint_unused_macro_definition = unused macro definition: `{$name}`
|
||||
|
||||
lint_unused_macro_use = unused `#[macro_use]` import
|
||||
|
||||
lint_unused_op = unused {$op} that must be used
|
||||
.label = the {$op} produces a value
|
||||
.suggestion = use `let _ = ...` to ignore the resulting value
|
||||
|
|
@ -654,3 +886,6 @@ lint_unused_result = unused result of type `{$ty}`
|
|||
|
||||
lint_variant_size_differences =
|
||||
enum variant is more than three times larger ({$largest} bytes) than the next largest
|
||||
|
||||
lint_wasm_c_abi =
|
||||
older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
|
||||
|
|
|
|||
|
|
@ -1,144 +0,0 @@
|
|||
use crate::{
|
||||
lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub},
|
||||
LateContext, LateLintPass, LintContext,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_lint! {
|
||||
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,edition2018
|
||||
/// # #![allow(unused)]
|
||||
/// [1, 2, 3].into_iter().for_each(|n| { *n; });
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
|
||||
/// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
|
||||
/// behave as `(&array).into_iter()`, returning an iterator over
|
||||
/// references, just like in Rust 1.52 and earlier.
|
||||
/// This only applies to the method call syntax `array.into_iter()`, not to
|
||||
/// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
|
||||
pub ARRAY_INTO_ITER,
|
||||
Warn,
|
||||
"detects calling `into_iter` on arrays in Rust 2015 and 2018",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
|
||||
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct ArrayIntoIter {
|
||||
for_expr_span: Span,
|
||||
}
|
||||
|
||||
impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
// Save the span of expressions in `for _ in expr` syntax,
|
||||
// so we can give a better suggestion for those later.
|
||||
if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
|
||||
if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
|
||||
if let hir::ExprKind::Path(hir::QPath::LangItem(
|
||||
hir::LangItem::IntoIterIntoIter,
|
||||
..,
|
||||
)) = &path.kind
|
||||
{
|
||||
self.for_expr_span = arg.span;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We only care about method call expressions.
|
||||
if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind {
|
||||
if call.ident.name != sym::into_iter {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the method call actually calls the libcore
|
||||
// `IntoIterator::into_iter`.
|
||||
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
||||
match cx.tcx.trait_of_item(def_id) {
|
||||
Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// As this is a method call expression, we have at least one argument.
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
|
||||
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
|
||||
|
||||
let Some(Adjustment { kind: Adjust::Borrow(_), target }) = adjustments.last() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let types =
|
||||
std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));
|
||||
|
||||
let mut found_array = false;
|
||||
|
||||
for ty in types {
|
||||
match ty.kind() {
|
||||
// If we run into a &[T; N] or &[T] first, there's nothing to warn about.
|
||||
// It'll resolve to the reference version.
|
||||
ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
|
||||
ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
|
||||
// Found an actual array type without matching a &[T; N] first.
|
||||
// This is the problematic case.
|
||||
ty::Array(..) => {
|
||||
found_array = true;
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if !found_array {
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit lint diagnostic.
|
||||
let target = match *target.kind() {
|
||||
ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
|
||||
ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
|
||||
// We know the original first argument type is an array type,
|
||||
// we know that the first adjustment was an autoref coercion
|
||||
// and we know that `IntoIterator` is the trait involved. The
|
||||
// array cannot be coerced to something other than a reference
|
||||
// to an array or to a slice.
|
||||
_ => bug!("array type coerced to something other than array or slice"),
|
||||
};
|
||||
let sub = if self.for_expr_span == expr.span {
|
||||
Some(ArrayIntoIterDiagSub::RemoveIntoIter {
|
||||
span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
})
|
||||
} else if receiver_ty.is_array() {
|
||||
Some(ArrayIntoIterDiagSub::UseExplicitIntoIter {
|
||||
start_span: expr.span.shrink_to_lo(),
|
||||
end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
cx.emit_span_lint(
|
||||
ARRAY_INTO_ITER,
|
||||
call.ident.span,
|
||||
ArrayIntoIterDiag { target, suggestion: call.ident.span, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,10 +30,10 @@ use crate::{
|
|||
BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
|
||||
BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
|
||||
BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
|
||||
BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
|
||||
BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
|
||||
BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
|
||||
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
|
||||
BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric,
|
||||
BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds,
|
||||
BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion,
|
||||
BuiltinTypeAliasWhereClause, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
|
||||
BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
|
||||
BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
|
||||
BuiltinWhileTrue, SuggestChangingAssocTypes,
|
||||
|
|
@ -60,7 +60,7 @@ use rustc_middle::ty::GenericArgKind;
|
|||
use rustc_middle::ty::TypeVisitableExt;
|
||||
use rustc_middle::ty::Upcast;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
|
||||
use rustc_session::lint::{BuiltinLintDiag, FutureIncompatibilityReason};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::Spanned;
|
||||
|
|
@ -2882,16 +2882,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
|
|||
let target_spans: MultiSpan =
|
||||
if spans.len() > 0 { spans.into() } else { (*template_span).into() };
|
||||
|
||||
cx.span_lint_with_diagnostics(
|
||||
NAMED_ASM_LABELS,
|
||||
Some(target_spans),
|
||||
fluent::lint_builtin_asm_labels,
|
||||
|_| {},
|
||||
BuiltinLintDiag::NamedAsmLabel(
|
||||
"only local labels of the form `<number>:` should be used in inline asm"
|
||||
.to_string(),
|
||||
),
|
||||
);
|
||||
cx.emit_span_lint(NAMED_ASM_LABELS, target_spans, BuiltinNamedAsmLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -527,30 +527,24 @@ pub struct EarlyContext<'a> {
|
|||
pub buffered: LintBuffer,
|
||||
}
|
||||
|
||||
pub trait LintContext {
|
||||
fn sess(&self) -> &Session;
|
||||
|
||||
impl EarlyContext<'_> {
|
||||
/// Emit a lint at the appropriate level, with an optional associated span and an existing
|
||||
/// diagnostic.
|
||||
///
|
||||
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
|
||||
#[rustc_lint_diagnostics]
|
||||
fn span_lint_with_diagnostics(
|
||||
pub fn span_lint_with_diagnostics(
|
||||
&self,
|
||||
lint: &'static Lint,
|
||||
span: Option<impl Into<MultiSpan>>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
|
||||
span: MultiSpan,
|
||||
diagnostic: BuiltinLintDiag,
|
||||
) {
|
||||
// We first generate a blank diagnostic.
|
||||
self.opt_span_lint(lint, span, msg, |db| {
|
||||
// Now, set up surrounding context.
|
||||
diagnostics::builtin(self.sess(), diagnostic, db);
|
||||
// Rewrap `db`, and pass control to the user.
|
||||
decorate(db)
|
||||
});
|
||||
diagnostics::emit_buffered_lint(self, lint, span, diagnostic)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait LintContext {
|
||||
fn sess(&self) -> &Session;
|
||||
|
||||
// FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
|
||||
// set the span in their `decorate` function (preferably using set_span).
|
||||
|
|
|
|||
|
|
@ -1,58 +1,57 @@
|
|||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
|
||||
use rustc_errors::{elided_lifetime_in_path_suggestion, Diag};
|
||||
use rustc_errors::{Applicability, SuggestionStyle};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_errors::{elided_lifetime_in_path_suggestion, DiagArgValue, MultiSpan};
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::{BuiltinLintDiag, Lint};
|
||||
use rustc_span::BytePos;
|
||||
|
||||
use crate::{lints, EarlyContext, LintContext as _};
|
||||
|
||||
mod check_cfg;
|
||||
|
||||
pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) {
|
||||
pub(super) fn emit_buffered_lint(
|
||||
ctx: &EarlyContext<'_>,
|
||||
lint: &'static Lint,
|
||||
span: MultiSpan,
|
||||
diagnostic: BuiltinLintDiag,
|
||||
) {
|
||||
let sess = ctx.sess();
|
||||
match diagnostic {
|
||||
BuiltinLintDiag::UnicodeTextFlow(span, content) => {
|
||||
BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
|
||||
let spans: Vec<_> = content
|
||||
.char_indices()
|
||||
.filter_map(|(i, c)| {
|
||||
TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
|
||||
let lo = span.lo() + BytePos(2 + i as u32);
|
||||
(c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
|
||||
let lo = comment_span.lo() + BytePos(2 + i as u32);
|
||||
(c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let (an, s) = match spans.len() {
|
||||
1 => ("an ", ""),
|
||||
_ => ("", "s"),
|
||||
};
|
||||
diag.span_label(
|
||||
let characters = spans
|
||||
.iter()
|
||||
.map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") })
|
||||
.collect();
|
||||
let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
|
||||
spans: spans.iter().map(|(_c, span)| *span).collect(),
|
||||
});
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
format!(
|
||||
"this comment contains {an}invisible unicode text flow control codepoint{s}",
|
||||
),
|
||||
);
|
||||
for (c, span) in &spans {
|
||||
diag.span_label(*span, format!("{c:?}"));
|
||||
}
|
||||
diag.note(
|
||||
"these kind of unicode codepoints change the way text flows on \
|
||||
applications that support them, but can cause confusion because they \
|
||||
change the order of characters on the screen",
|
||||
);
|
||||
if !spans.is_empty() {
|
||||
diag.multipart_suggestion_with_style(
|
||||
"if their presence wasn't intentional, you can remove them",
|
||||
spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(),
|
||||
Applicability::MachineApplicable,
|
||||
SuggestionStyle::HideCodeAlways,
|
||||
);
|
||||
}
|
||||
lints::UnicodeTextFlow {
|
||||
comment_span,
|
||||
characters,
|
||||
suggestions,
|
||||
num_codepoints: spans.len(),
|
||||
},
|
||||
)
|
||||
}
|
||||
BuiltinLintDiag::Normal => (),
|
||||
BuiltinLintDiag::AbsPathWithModule(span) => {
|
||||
let (sugg, app) = match sess.source_map().span_to_snippet(span) {
|
||||
BuiltinLintDiag::AbsPathWithModule(mod_span) => {
|
||||
let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) {
|
||||
Ok(ref s) => {
|
||||
// FIXME(Manishearth) ideally the emitting code
|
||||
// can tell us whether or not this is global
|
||||
|
|
@ -62,160 +61,207 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
|||
}
|
||||
Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
|
||||
};
|
||||
diag.span_suggestion(span, "use `crate`", sugg, app);
|
||||
}
|
||||
BuiltinLintDiag::ProcMacroDeriveResolutionFallback(span) => {
|
||||
diag.span_label(
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
"names from parent modules are not accessible without an explicit import",
|
||||
lints::AbsPathWithModule {
|
||||
sugg: lints::AbsPathWithModuleSugg {
|
||||
span: mod_span,
|
||||
applicability,
|
||||
replacement,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
|
||||
diag.span_note(span_def, "the macro is defined here");
|
||||
}
|
||||
BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => ctx
|
||||
.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident },
|
||||
),
|
||||
BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => ctx
|
||||
.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def },
|
||||
),
|
||||
BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
|
||||
diag.subdiagnostic(
|
||||
sess.dcx(),
|
||||
elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
),
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::ElidedLifetimesInPaths {
|
||||
subdiag: elided_lifetime_in_path_suggestion(
|
||||
sess.source_map(),
|
||||
n,
|
||||
path_span,
|
||||
incl_angl_brckt,
|
||||
insertion_span,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => {
|
||||
diag.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect);
|
||||
BuiltinLintDiag::UnknownCrateTypes { span, candidate } => {
|
||||
let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate });
|
||||
ctx.emit_span_lint(lint, span, lints::UnknownCrateTypes { sugg });
|
||||
}
|
||||
BuiltinLintDiag::UnusedImports(message, replaces, in_test_module) => {
|
||||
if !replaces.is_empty() {
|
||||
diag.tool_only_multipart_suggestion(
|
||||
message,
|
||||
replaces,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::UnusedImports {
|
||||
remove_whole_use,
|
||||
num_to_remove,
|
||||
remove_spans,
|
||||
test_module_span,
|
||||
span_snippets,
|
||||
} => {
|
||||
let sugg = if remove_whole_use {
|
||||
lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
|
||||
} else {
|
||||
lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
|
||||
};
|
||||
let test_module_span =
|
||||
test_module_span.map(|span| sess.source_map().guess_head_span(span));
|
||||
|
||||
if let Some(span) = in_test_module {
|
||||
diag.span_help(
|
||||
sess.source_map().guess_head_span(span),
|
||||
"if this is a test module, consider adding a `#[cfg(test)]` to the containing module",
|
||||
);
|
||||
}
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::UnusedImports {
|
||||
sugg,
|
||||
test_module_span,
|
||||
num_snippets: span_snippets.len(),
|
||||
span_snippets: DiagArgValue::StrListSepByAnd(
|
||||
span_snippets.into_iter().map(Cow::Owned).collect(),
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::RedundantImport(spans, ident) => {
|
||||
for (span, is_imported) in spans {
|
||||
let introduced = if is_imported { "imported" } else { "defined" };
|
||||
let span_msg = if span.is_dummy() { "by the extern prelude" } else { "here" };
|
||||
diag.span_label(
|
||||
span,
|
||||
format!("the item `{ident}` is already {introduced} {span_msg}"),
|
||||
);
|
||||
}
|
||||
let subs = spans
|
||||
.into_iter()
|
||||
.map(|(span, is_imported)| {
|
||||
(match (span.is_dummy(), is_imported) {
|
||||
(false, true) => lints::RedundantImportSub::ImportedHere,
|
||||
(false, false) => lints::RedundantImportSub::DefinedHere,
|
||||
(true, true) => lints::RedundantImportSub::ImportedPrelude,
|
||||
(true, false) => lints::RedundantImportSub::DefinedPrelude,
|
||||
})(span)
|
||||
})
|
||||
.collect();
|
||||
ctx.emit_span_lint(lint, span, lints::RedundantImport { subs, ident });
|
||||
}
|
||||
BuiltinLintDiag::DeprecatedMacro(suggestion, span) => {
|
||||
stability::deprecation_suggestion(diag, "macro", suggestion, span)
|
||||
}
|
||||
BuiltinLintDiag::UnusedDocComment(span) => {
|
||||
diag.span_label(span, "rustdoc does not generate documentation for macro invocations");
|
||||
diag.help("to document an item produced by a macro, \
|
||||
the macro must produce the documentation as part of its expansion");
|
||||
}
|
||||
BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident) => {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"remove `mut` from the parameter",
|
||||
ident,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::MissingAbi(span, default_abi) => {
|
||||
diag.span_label(span, "ABI should be specified here");
|
||||
diag.help(format!("the default ABI is {}", default_abi.name()));
|
||||
}
|
||||
BuiltinLintDiag::LegacyDeriveHelpers(span) => {
|
||||
diag.span_label(span, "the attribute is introduced here");
|
||||
}
|
||||
BuiltinLintDiag::ProcMacroBackCompat(note) => {
|
||||
diag.note(note);
|
||||
}
|
||||
BuiltinLintDiag::OrPatternsBackCompat(span, suggestion) => {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"use pat_param to preserve semantics",
|
||||
BuiltinLintDiag::DeprecatedMacro {
|
||||
suggestion,
|
||||
suggestion_span,
|
||||
note,
|
||||
path,
|
||||
since_kind,
|
||||
} => {
|
||||
let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion {
|
||||
span: suggestion_span,
|
||||
kind: "macro".to_owned(),
|
||||
suggestion,
|
||||
Applicability::MachineApplicable,
|
||||
});
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::ReservedPrefix(span) => {
|
||||
diag.span_label(span, "unknown prefix");
|
||||
diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
|
||||
" ",
|
||||
Applicability::MachineApplicable,
|
||||
BuiltinLintDiag::UnusedDocComment(attr_span) => {
|
||||
ctx.emit_span_lint(lint, span, lints::UnusedDocComment { span: attr_span });
|
||||
}
|
||||
BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => {
|
||||
let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span };
|
||||
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
if is_foreign {
|
||||
lints::PatternsInFnsWithoutBody::Foreign { sub }
|
||||
} else {
|
||||
lints::PatternsInFnsWithoutBody::Bodiless { sub }
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::MissingAbi(label_span, default_abi) => {
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::MissingAbi { span: label_span, default_abi: default_abi.name() },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::LegacyDeriveHelpers(label_span) => {
|
||||
ctx.emit_span_lint(lint, span, lints::LegacyDeriveHelpers { span: label_span });
|
||||
}
|
||||
BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => {
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::ProcMacroBackCompat { crate_name, fixed_version },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => {
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::OrPatternsBackCompat { span: suggestion_span, suggestion },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::ReservedPrefix(label_span, prefix) => {
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::ReservedPrefix {
|
||||
label: label_span,
|
||||
suggestion: label_span.shrink_to_hi(),
|
||||
prefix,
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => {
|
||||
diag.span_note(
|
||||
invoc_span,
|
||||
format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
|
||||
if is_trailing {
|
||||
diag.note("macro invocations at the end of a block are treated as expressions");
|
||||
diag.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
|
||||
}
|
||||
}
|
||||
BuiltinLintDiag::BreakWithLabelAndLoop(span) => {
|
||||
diag.multipart_suggestion(
|
||||
"wrap this expression in parentheses",
|
||||
vec![
|
||||
(span.shrink_to_lo(), "(".to_string()),
|
||||
(span.shrink_to_hi(), ")".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::NamedAsmLabel(help) => {
|
||||
diag.help(help);
|
||||
diag.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
|
||||
BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
|
||||
ctx.emit_span_lint(lint, span, lints::TrailingMacro { is_trailing, name });
|
||||
}
|
||||
BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => {
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::BreakWithLabelAndLoop {
|
||||
sub: lints::BreakWithLabelAndLoopSub {
|
||||
left: sugg_span.shrink_to_lo(),
|
||||
right: sugg_span.shrink_to_hi(),
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::UnexpectedCfgName(name, value) => {
|
||||
check_cfg::unexpected_cfg_name(sess, diag, name, value)
|
||||
ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_name(sess, name, value));
|
||||
}
|
||||
BuiltinLintDiag::UnexpectedCfgValue(name, value) => {
|
||||
check_cfg::unexpected_cfg_value(sess, diag, name, value)
|
||||
ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_value(sess, name, value));
|
||||
}
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg) => {
|
||||
let left_sp = diag.span.primary_span().unwrap();
|
||||
match sugg {
|
||||
Some((right_sp, sugg)) => diag.multipart_suggestion(
|
||||
"move it to the end of the type declaration",
|
||||
vec![(left_sp, String::new()), (right_sp, sugg)],
|
||||
Applicability::MachineApplicable,
|
||||
),
|
||||
None => diag.span_suggestion(
|
||||
left_sp,
|
||||
"remove this `where`",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
),
|
||||
BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
|
||||
let suggestion = match sugg {
|
||||
Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
|
||||
left: left_sp,
|
||||
right: right_sp,
|
||||
sugg,
|
||||
},
|
||||
None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp },
|
||||
};
|
||||
diag.note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information");
|
||||
ctx.emit_span_lint(lint, span, lints::DeprecatedWhereClauseLocation { suggestion });
|
||||
}
|
||||
BuiltinLintDiag::SingleUseLifetime {
|
||||
param_span,
|
||||
use_span: Some((use_span, elide)),
|
||||
deletion_span,
|
||||
ident,
|
||||
} => {
|
||||
debug!(?param_span, ?use_span, ?deletion_span);
|
||||
diag.span_label(param_span, "this lifetime...");
|
||||
diag.span_label(use_span, "...is used only here");
|
||||
if let Some(deletion_span) = deletion_span {
|
||||
let msg = "elide the single-use lifetime";
|
||||
let suggestion = if let Some(deletion_span) = deletion_span {
|
||||
let (use_span, replace_lt) = if elide {
|
||||
let use_span = sess.source_map().span_extend_while_whitespace(use_span);
|
||||
(use_span, String::new())
|
||||
|
|
@ -226,24 +272,22 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
|||
|
||||
// issue 107998 for the case such as a wrong function pointer type
|
||||
// `deletion_span` is empty and there is no need to report lifetime uses here
|
||||
let suggestions = if deletion_span.is_empty() {
|
||||
vec![(use_span, replace_lt)]
|
||||
} else {
|
||||
vec![(deletion_span, String::new()), (use_span, replace_lt)]
|
||||
};
|
||||
diag.multipart_suggestion(msg, suggestions, Applicability::MachineApplicable);
|
||||
}
|
||||
let deletion_span =
|
||||
if deletion_span.is_empty() { None } else { Some(deletion_span) };
|
||||
Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::SingleUseLifetime { suggestion, param_span, use_span, ident },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::SingleUseLifetime { param_span: _, use_span: None, deletion_span } => {
|
||||
BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => {
|
||||
debug!(?deletion_span);
|
||||
if let Some(deletion_span) = deletion_span {
|
||||
diag.span_suggestion(
|
||||
deletion_span,
|
||||
"elide the unused lifetime",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
ctx.emit_span_lint(lint, span, lints::UnusedLifetime { deletion_span, ident });
|
||||
}
|
||||
BuiltinLintDiag::NamedArgumentUsedPositionally {
|
||||
position_sp_to_replace,
|
||||
|
|
@ -252,19 +296,12 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
|||
named_arg_name,
|
||||
is_formatting_arg,
|
||||
} => {
|
||||
diag.span_label(
|
||||
named_arg_sp,
|
||||
"this named argument is referred to by position in formatting string",
|
||||
);
|
||||
if let Some(positional_arg_for_msg) = position_sp_for_msg {
|
||||
let msg = format!(
|
||||
"this formatting argument uses named argument `{named_arg_name}` by position"
|
||||
);
|
||||
diag.span_label(positional_arg_for_msg, msg);
|
||||
}
|
||||
|
||||
if let Some(positional_arg_to_replace) = position_sp_to_replace {
|
||||
let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
|
||||
let (suggestion, name) = if let Some(positional_arg_to_replace) = position_sp_to_replace
|
||||
{
|
||||
let mut name = named_arg_name.clone();
|
||||
if is_formatting_arg {
|
||||
name.push('$')
|
||||
};
|
||||
let span_to_replace = if let Ok(positional_arg_content) =
|
||||
sess.source_map().span_to_snippet(positional_arg_to_replace)
|
||||
&& positional_arg_content.starts_with(':')
|
||||
|
|
@ -273,31 +310,40 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
|||
} else {
|
||||
positional_arg_to_replace
|
||||
};
|
||||
diag.span_suggestion_verbose(
|
||||
span_to_replace,
|
||||
"use the named argument by name to avoid ambiguity",
|
||||
(Some(span_to_replace), name)
|
||||
} else {
|
||||
(None, String::new())
|
||||
};
|
||||
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::NamedArgumentUsedPositionally {
|
||||
named_arg_sp,
|
||||
position_label_sp: position_sp_for_msg,
|
||||
suggestion,
|
||||
name,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
named_arg_name,
|
||||
},
|
||||
)
|
||||
}
|
||||
BuiltinLintDiag::ByteSliceInPackedStructWithDerive => {
|
||||
diag.help("consider implementing the trait by hand, or remove the `packed` attribute");
|
||||
BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => {
|
||||
ctx.emit_span_lint(lint, span, lints::ByteSliceInPackedStructWithDerive { ty })
|
||||
}
|
||||
BuiltinLintDiag::UnusedExternCrate { removal_span } => {
|
||||
diag.span_suggestion(removal_span, "remove it", "", Applicability::MachineApplicable);
|
||||
ctx.emit_span_lint(lint, span, lints::UnusedExternCrate { removal_span })
|
||||
}
|
||||
BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => {
|
||||
let suggestion_span = vis_span.between(ident_span);
|
||||
diag.span_suggestion_verbose(
|
||||
suggestion_span,
|
||||
"convert it to a `use`",
|
||||
if vis_span.is_empty() { "use " } else { " use " },
|
||||
Applicability::MachineApplicable,
|
||||
let code = if vis_span.is_empty() { "use " } else { " use " };
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::ExternCrateNotIdiomatic { span: suggestion_span, code },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => {
|
||||
rustc_errors::report_ambiguity_error(diag, ambiguity);
|
||||
ctx.emit_span_lint(lint, span, lints::AmbiguousGlobImports { ambiguity });
|
||||
}
|
||||
BuiltinLintDiag::AmbiguousGlobReexports {
|
||||
name,
|
||||
|
|
@ -305,15 +351,15 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
|||
first_reexport_span,
|
||||
duplicate_reexport_span,
|
||||
} => {
|
||||
diag.span_label(
|
||||
first_reexport_span,
|
||||
format!("the name `{name}` in the {namespace} namespace is first re-exported here"),
|
||||
);
|
||||
diag.span_label(
|
||||
duplicate_reexport_span,
|
||||
format!(
|
||||
"but the name `{name}` in the {namespace} namespace is also re-exported here"
|
||||
),
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::AmbiguousGlobReexports {
|
||||
first_reexport: first_reexport_span,
|
||||
duplicate_reexport: duplicate_reexport_span,
|
||||
name,
|
||||
namespace,
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::HiddenGlobReexports {
|
||||
|
|
@ -322,38 +368,127 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
|
|||
glob_reexport_span,
|
||||
private_item_span,
|
||||
} => {
|
||||
diag.span_note(glob_reexport_span, format!("the name `{name}` in the {namespace} namespace is supposed to be publicly re-exported here"));
|
||||
diag.span_note(private_item_span, "but the private item here shadows it".to_owned());
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::HiddenGlobReexports {
|
||||
glob_reexport: glob_reexport_span,
|
||||
private_item: private_item_span,
|
||||
|
||||
name,
|
||||
namespace,
|
||||
},
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::UnusedQualifications { removal_span } => {
|
||||
diag.span_suggestion_verbose(
|
||||
removal_span,
|
||||
"remove the unnecessary path segments",
|
||||
"",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
ctx.emit_span_lint(lint, span, lints::UnusedQualifications { removal_span });
|
||||
}
|
||||
BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span } => {
|
||||
diag.span_suggestion_verbose(
|
||||
if elided { span.shrink_to_hi() } else { span },
|
||||
"use the `'static` lifetime",
|
||||
if elided { "'static " } else { "'static" },
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::RedundantImportVisibility { max_vis, span } => {
|
||||
diag.span_note(span, format!("the most public imported item is `{max_vis}`"));
|
||||
diag.help(
|
||||
"reduce the glob import's visibility or increase visibility of imported items",
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::MaybeTypo { span, name } => {
|
||||
diag.span_suggestion_verbose(
|
||||
BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => {
|
||||
let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span };
|
||||
let code = if elided { "'static " } else { "'static" };
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
"an attribute with a similar name exists",
|
||||
name,
|
||||
Applicability::MachineApplicable,
|
||||
lints::AssociatedConstElidedLifetime { span: lt_span, code, elided },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => {
|
||||
ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis },
|
||||
);
|
||||
}
|
||||
BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => {
|
||||
let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg {
|
||||
span: typo_span,
|
||||
typo_name,
|
||||
});
|
||||
ctx.emit_span_lint(lint, span, lints::UnknownDiagnosticAttribute { typo });
|
||||
}
|
||||
BuiltinLintDiag::MacroUseDeprecated => {
|
||||
ctx.emit_span_lint(lint, span, lints::MacroUseDeprecated)
|
||||
}
|
||||
BuiltinLintDiag::UnusedMacroUse => ctx.emit_span_lint(lint, span, lints::UnusedMacroUse),
|
||||
BuiltinLintDiag::PrivateExternCrateReexport(ident) => {
|
||||
ctx.emit_span_lint(lint, span, lints::PrivateExternCrateReexport { ident })
|
||||
}
|
||||
BuiltinLintDiag::UnusedLabel => ctx.emit_span_lint(lint, span, lints::UnusedLabel),
|
||||
BuiltinLintDiag::MacroIsPrivate(ident) => {
|
||||
ctx.emit_span_lint(lint, span, lints::MacroIsPrivate { ident })
|
||||
}
|
||||
BuiltinLintDiag::UnusedMacroDefinition(name) => {
|
||||
ctx.emit_span_lint(lint, span, lints::UnusedMacroDefinition { name })
|
||||
}
|
||||
BuiltinLintDiag::MacroRuleNeverUsed(n, name) => {
|
||||
ctx.emit_span_lint(lint, span, lints::MacroRuleNeverUsed { n: n + 1, name })
|
||||
}
|
||||
BuiltinLintDiag::UnstableFeature(msg) => {
|
||||
ctx.emit_span_lint(lint, span, lints::UnstableFeature { msg })
|
||||
}
|
||||
BuiltinLintDiag::AvoidUsingIntelSyntax => {
|
||||
ctx.emit_span_lint(lint, span, lints::AvoidIntelSyntax)
|
||||
}
|
||||
BuiltinLintDiag::AvoidUsingAttSyntax => {
|
||||
ctx.emit_span_lint(lint, span, lints::AvoidAttSyntax)
|
||||
}
|
||||
BuiltinLintDiag::IncompleteInclude => {
|
||||
ctx.emit_span_lint(lint, span, lints::IncompleteInclude)
|
||||
}
|
||||
BuiltinLintDiag::UnnameableTestItems => {
|
||||
ctx.emit_span_lint(lint, span, lints::UnnameableTestItems)
|
||||
}
|
||||
BuiltinLintDiag::DuplicateMacroAttribute => {
|
||||
ctx.emit_span_lint(lint, span, lints::DuplicateMacroAttribute)
|
||||
}
|
||||
BuiltinLintDiag::CfgAttrNoAttributes => {
|
||||
ctx.emit_span_lint(lint, span, lints::CfgAttrNoAttributes)
|
||||
}
|
||||
BuiltinLintDiag::CrateTypeInCfgAttr => {
|
||||
ctx.emit_span_lint(lint, span, lints::CrateTypeInCfgAttr)
|
||||
}
|
||||
BuiltinLintDiag::CrateNameInCfgAttr => {
|
||||
ctx.emit_span_lint(lint, span, lints::CrateNameInCfgAttr)
|
||||
}
|
||||
BuiltinLintDiag::MissingFragmentSpecifier => {
|
||||
ctx.emit_span_lint(lint, span, lints::MissingFragmentSpecifier)
|
||||
}
|
||||
BuiltinLintDiag::MetaVariableStillRepeating(name) => {
|
||||
ctx.emit_span_lint(lint, span, lints::MetaVariableStillRepeating { name })
|
||||
}
|
||||
BuiltinLintDiag::MetaVariableWrongOperator => {
|
||||
ctx.emit_span_lint(lint, span, lints::MetaVariableWrongOperator)
|
||||
}
|
||||
BuiltinLintDiag::DuplicateMatcherBinding => {
|
||||
ctx.emit_span_lint(lint, span, lints::DuplicateMatcherBinding)
|
||||
}
|
||||
BuiltinLintDiag::UnknownMacroVariable(name) => {
|
||||
ctx.emit_span_lint(lint, span, lints::UnknownMacroVariable { name })
|
||||
}
|
||||
BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::UnusedCrateDependency { extern_crate, local_crate },
|
||||
),
|
||||
BuiltinLintDiag::WasmCAbi => ctx.emit_span_lint(lint, span, lints::WasmCAbi),
|
||||
BuiltinLintDiag::IllFormedAttributeInput { suggestions } => ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
lints::IllFormedAttributeInput {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||
),
|
||||
},
|
||||
),
|
||||
BuiltinLintDiag::InnerAttributeUnstable { is_macro } => ctx.emit_span_lint(
|
||||
lint,
|
||||
span,
|
||||
if is_macro {
|
||||
lints::InnerAttributeUnstable::InnerMacroAttribute
|
||||
} else {
|
||||
lints::InnerAttributeUnstable::CustomInnerAttribute
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,52 @@
|
|||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::{config::ExpectedValues, Session};
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
use rustc_span::{sym, Span, Symbol};
|
||||
|
||||
use crate::lints;
|
||||
|
||||
const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
|
||||
|
||||
fn check_cfg_expected_note(
|
||||
fn sort_and_truncate_possibilities(
|
||||
sess: &Session,
|
||||
possibilities: &[Symbol],
|
||||
type_: &str,
|
||||
name: Option<Symbol>,
|
||||
suffix: &str,
|
||||
) -> String {
|
||||
use std::fmt::Write;
|
||||
|
||||
mut possibilities: Vec<Symbol>,
|
||||
) -> (Vec<Symbol>, usize) {
|
||||
let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
|
||||
possibilities.len()
|
||||
} else {
|
||||
std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
|
||||
};
|
||||
|
||||
let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
|
||||
possibilities.sort();
|
||||
possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
|
||||
|
||||
let and_more = possibilities.len().saturating_sub(n_possibilities);
|
||||
let possibilities = possibilities[..n_possibilities].join("`, `");
|
||||
possibilities.truncate(n_possibilities);
|
||||
(possibilities, and_more)
|
||||
}
|
||||
|
||||
let mut note = String::with_capacity(50 + possibilities.len());
|
||||
enum EscapeQuotes {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
write!(&mut note, "expected {type_}").unwrap();
|
||||
if let Some(name) = name {
|
||||
write!(&mut note, " for `{name}`").unwrap();
|
||||
fn to_check_cfg_arg(name: Symbol, value: Option<Symbol>, quotes: EscapeQuotes) -> String {
|
||||
if let Some(value) = value {
|
||||
let value = str::escape_debug(value.as_str()).to_string();
|
||||
let values = match quotes {
|
||||
EscapeQuotes::Yes => format!("\\\"{}\\\"", value.replace("\"", "\\\\\\\\\"")),
|
||||
EscapeQuotes::No => format!("\"{value}\""),
|
||||
};
|
||||
format!("cfg({name}, values({values}))")
|
||||
} else {
|
||||
format!("cfg({name})")
|
||||
}
|
||||
write!(&mut note, " are: {suffix}`{possibilities}`").unwrap();
|
||||
if and_more > 0 {
|
||||
write!(&mut note, " and {and_more} more").unwrap();
|
||||
}
|
||||
|
||||
note
|
||||
}
|
||||
|
||||
pub(super) fn unexpected_cfg_name(
|
||||
sess: &Session,
|
||||
diag: &mut Diag<'_, ()>,
|
||||
(name, name_span): (Symbol, Span),
|
||||
value: Option<(Symbol, Span)>,
|
||||
) {
|
||||
) -> lints::UnexpectedCfgName {
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
let possibilities: Vec<Symbol> = sess.psess.check_config.expecteds.keys().copied().collect();
|
||||
|
||||
|
|
@ -69,116 +69,122 @@ pub(super) fn unexpected_cfg_name(
|
|||
let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
|
||||
let mut is_feature_cfg = name == sym::feature;
|
||||
|
||||
if is_feature_cfg && is_from_cargo {
|
||||
diag.help("consider defining some features in `Cargo.toml`");
|
||||
let code_sugg = if is_feature_cfg && is_from_cargo {
|
||||
lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures
|
||||
// Suggest the most probable if we found one
|
||||
} else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
|
||||
is_feature_cfg |= best_match == sym::feature;
|
||||
|
||||
if let Some(ExpectedValues::Some(best_match_values)) =
|
||||
sess.psess.check_config.expecteds.get(&best_match)
|
||||
{
|
||||
// We will soon sort, so the initial order does not matter.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
let mut possibilities =
|
||||
best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>();
|
||||
possibilities.sort();
|
||||
let mut possibilities = best_match_values.iter().flatten().collect::<Vec<_>>();
|
||||
possibilities.sort_by_key(|s| s.as_str());
|
||||
|
||||
let get_possibilities_sub = || {
|
||||
if !possibilities.is_empty() {
|
||||
let possibilities =
|
||||
possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
|
||||
Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut should_print_possibilities = true;
|
||||
if let Some((value, value_span)) = value {
|
||||
if best_match_values.contains(&Some(value)) {
|
||||
diag.span_suggestion(
|
||||
name_span,
|
||||
"there is a config with a similar name and value",
|
||||
best_match,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
should_print_possibilities = false;
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
|
||||
span: name_span,
|
||||
code: best_match.to_string(),
|
||||
}
|
||||
} else if best_match_values.contains(&None) {
|
||||
diag.span_suggestion(
|
||||
name_span.to(value_span),
|
||||
"there is a config with a similar name and no value",
|
||||
best_match,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
should_print_possibilities = false;
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
|
||||
span: name_span.to(value_span),
|
||||
code: best_match.to_string(),
|
||||
}
|
||||
} else if let Some(first_value) = possibilities.first() {
|
||||
diag.span_suggestion(
|
||||
name_span.to(value_span),
|
||||
"there is a config with a similar name and different values",
|
||||
format!("{best_match} = \"{first_value}\""),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
|
||||
span: name_span.to(value_span),
|
||||
code: format!("{best_match} = \"{first_value}\""),
|
||||
expected: get_possibilities_sub(),
|
||||
}
|
||||
} else {
|
||||
diag.span_suggestion(
|
||||
name_span.to(value_span),
|
||||
"there is a config with a similar name and different values",
|
||||
best_match,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
};
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
|
||||
span: name_span.to(value_span),
|
||||
code: best_match.to_string(),
|
||||
expected: get_possibilities_sub(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
diag.span_suggestion(
|
||||
name_span,
|
||||
"there is a config with a similar name",
|
||||
best_match,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
if !possibilities.is_empty() && should_print_possibilities {
|
||||
let possibilities = possibilities.join("`, `");
|
||||
diag.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
|
||||
span: name_span,
|
||||
code: best_match.to_string(),
|
||||
expected: get_possibilities_sub(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
diag.span_suggestion(
|
||||
name_span,
|
||||
"there is a config with a similar name",
|
||||
best_match,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
is_feature_cfg |= best_match == sym::feature;
|
||||
} else {
|
||||
if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
|
||||
names_possibilities.sort();
|
||||
for cfg_name in names_possibilities.iter() {
|
||||
diag.span_suggestion(
|
||||
name_span,
|
||||
"found config with similar value",
|
||||
format!("{cfg_name} = \"{name}\""),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
|
||||
span: name_span,
|
||||
code: best_match.to_string(),
|
||||
expected: None,
|
||||
}
|
||||
}
|
||||
if !possibilities.is_empty() {
|
||||
diag.help_once(check_cfg_expected_note(sess, &possibilities, "names", None, ""));
|
||||
}
|
||||
}
|
||||
|
||||
let inst = if let Some((value, _value_span)) = value {
|
||||
let pre = if is_from_cargo { "\\" } else { "" };
|
||||
format!("cfg({name}, values({pre}\"{value}{pre}\"))")
|
||||
} else {
|
||||
format!("cfg({name})")
|
||||
let similar_values = if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
|
||||
names_possibilities.sort();
|
||||
names_possibilities
|
||||
.iter()
|
||||
.map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue {
|
||||
span: name_span,
|
||||
code: format!("{cfg_name} = \"{name}\""),
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let expected_names = if !possibilities.is_empty() {
|
||||
let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities);
|
||||
Some(lints::unexpected_cfg_name::ExpectedNames {
|
||||
possibilities: possibilities.into(),
|
||||
and_more,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_name::CodeSuggestion::SimilarValues {
|
||||
with_similar_values: similar_values,
|
||||
expected_names,
|
||||
}
|
||||
};
|
||||
|
||||
if is_from_cargo {
|
||||
if !is_feature_cfg {
|
||||
diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
|
||||
}
|
||||
diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration");
|
||||
let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
|
||||
|
||||
let invocation_help = if is_from_cargo {
|
||||
let sub = if !is_feature_cfg {
|
||||
Some(lints::UnexpectedCfgCargoHelp::new(
|
||||
&inst(EscapeQuotes::No),
|
||||
&inst(EscapeQuotes::Yes),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_name::InvocationHelp::Cargo { sub }
|
||||
} else {
|
||||
diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
|
||||
diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration");
|
||||
}
|
||||
lints::unexpected_cfg_name::InvocationHelp::Rustc(lints::UnexpectedCfgRustcHelp::new(
|
||||
&inst(EscapeQuotes::No),
|
||||
))
|
||||
};
|
||||
|
||||
lints::UnexpectedCfgName { code_sugg, invocation_help, name }
|
||||
}
|
||||
|
||||
pub(super) fn unexpected_cfg_value(
|
||||
sess: &Session,
|
||||
diag: &mut Diag<'_, ()>,
|
||||
(name, name_span): (Symbol, Span),
|
||||
value: Option<(Symbol, Span)>,
|
||||
) {
|
||||
) -> lints::UnexpectedCfgValue {
|
||||
let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else {
|
||||
bug!(
|
||||
"it shouldn't be possible to have a diagnostic on a value whose name is not in values"
|
||||
|
|
@ -198,81 +204,90 @@ pub(super) fn unexpected_cfg_value(
|
|||
|
||||
// Show the full list if all possible values for a given name, but don't do it
|
||||
// for names as the possibilities could be very long
|
||||
if !possibilities.is_empty() {
|
||||
diag.note(check_cfg_expected_note(
|
||||
sess,
|
||||
&possibilities,
|
||||
"values",
|
||||
Some(name),
|
||||
if have_none_possibility { "(none), " } else { "" },
|
||||
));
|
||||
let code_sugg = if !possibilities.is_empty() {
|
||||
let expected_values = {
|
||||
let (possibilities, and_more) =
|
||||
sort_and_truncate_possibilities(sess, possibilities.clone());
|
||||
lints::unexpected_cfg_value::ExpectedValues {
|
||||
name,
|
||||
have_none_possibility,
|
||||
possibilities: possibilities.into(),
|
||||
and_more,
|
||||
}
|
||||
};
|
||||
|
||||
if let Some((value, value_span)) = value {
|
||||
let suggestion = if let Some((value, value_span)) = value {
|
||||
// Suggest the most probable if we found one
|
||||
if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
|
||||
diag.span_suggestion(
|
||||
value_span,
|
||||
"there is a expected value with a similar name",
|
||||
format!("\"{best_match}\""),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
|
||||
span: value_span,
|
||||
best_match,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if let &[first_possibility] = &possibilities[..] {
|
||||
diag.span_suggestion(
|
||||
name_span.shrink_to_hi(),
|
||||
"specify a config value",
|
||||
format!(" = \"{first_possibility}\""),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
} else if have_none_possibility {
|
||||
diag.note(format!("no expected value for `{name}`"));
|
||||
if let Some((_value, value_span)) = value {
|
||||
diag.span_suggestion(
|
||||
name_span.shrink_to_hi().to(value_span),
|
||||
"remove the value",
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
diag.note(format!("no expected values for `{name}`"));
|
||||
Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
|
||||
span: name_span.shrink_to_hi(),
|
||||
first_possibility,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let sp = if let Some((_value, value_span)) = value {
|
||||
lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
|
||||
} else if have_none_possibility {
|
||||
let suggestion =
|
||||
value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion {
|
||||
span: name_span.shrink_to_hi().to(value_span),
|
||||
});
|
||||
lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
|
||||
} else {
|
||||
let span = if let Some((_value, value_span)) = value {
|
||||
name_span.to(value_span)
|
||||
} else {
|
||||
name_span
|
||||
};
|
||||
diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect);
|
||||
}
|
||||
let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span };
|
||||
lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
|
||||
};
|
||||
|
||||
// We don't want to suggest adding values to well known names
|
||||
// since those are defined by rustc it-self. Users can still
|
||||
// do it if they want, but should not encourage them.
|
||||
let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
|
||||
|
||||
let inst = if let Some((value, _value_span)) = value {
|
||||
let pre = if is_from_cargo { "\\" } else { "" };
|
||||
format!("cfg({name}, values({pre}\"{value}{pre}\"))")
|
||||
} else {
|
||||
format!("cfg({name})")
|
||||
};
|
||||
let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
|
||||
|
||||
if is_from_cargo {
|
||||
if name == sym::feature {
|
||||
let invocation_help = if is_from_cargo {
|
||||
let help = if name == sym::feature {
|
||||
if let Some((value, _value_span)) = value {
|
||||
diag.help(format!("consider adding `{value}` as a feature in `Cargo.toml`"));
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value })
|
||||
} else {
|
||||
diag.help("consider defining some features in `Cargo.toml`");
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
|
||||
}
|
||||
} else if !is_cfg_a_well_know_name {
|
||||
diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
|
||||
}
|
||||
diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration");
|
||||
Some(lints::unexpected_cfg_value::CargoHelp::Other(lints::UnexpectedCfgCargoHelp::new(
|
||||
&inst(EscapeQuotes::No),
|
||||
&inst(EscapeQuotes::Yes),
|
||||
)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Cargo(help)
|
||||
} else {
|
||||
if !is_cfg_a_well_know_name {
|
||||
diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
|
||||
}
|
||||
diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration");
|
||||
let help = if !is_cfg_a_well_know_name {
|
||||
Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
lints::unexpected_cfg_value::InvocationHelp::Rustc(help)
|
||||
};
|
||||
|
||||
lints::UnexpectedCfgValue {
|
||||
code_sugg,
|
||||
invocation_help,
|
||||
has_value: value.is_some(),
|
||||
value: value.map_or_else(String::new, |(v, _span)| v.to_string()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
//! upon. As the ast is traversed, this keeps track of the current lint level
|
||||
//! for all lint attributes.
|
||||
|
||||
use crate::context::{EarlyContext, LintContext, LintStore};
|
||||
use crate::context::{EarlyContext, LintStore};
|
||||
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{self as ast_visit, walk_list, Visitor};
|
||||
|
|
@ -44,14 +44,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
|
|||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
fn inlined_check_id(&mut self, id: ast::NodeId) {
|
||||
for early_lint in self.context.buffered.take(id) {
|
||||
let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint;
|
||||
self.context.span_lint_with_diagnostics(
|
||||
lint_id.lint,
|
||||
Some(span),
|
||||
msg,
|
||||
|_| {},
|
||||
diagnostic,
|
||||
);
|
||||
let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
|
||||
self.context.span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
mod array_into_iter;
|
||||
mod async_fn_in_trait;
|
||||
pub mod builtin;
|
||||
mod context;
|
||||
|
|
@ -76,18 +75,18 @@ mod passes;
|
|||
mod ptr_nulls;
|
||||
mod redundant_semicolon;
|
||||
mod reference_casting;
|
||||
mod shadowed_into_iter;
|
||||
mod traits;
|
||||
mod types;
|
||||
mod unit_bindings;
|
||||
mod unused;
|
||||
|
||||
pub use array_into_iter::ARRAY_INTO_ITER;
|
||||
pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
|
||||
|
||||
use rustc_hir::def_id::LocalModDefId;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
use array_into_iter::ArrayIntoIter;
|
||||
use async_fn_in_trait::AsyncFnInTrait;
|
||||
use builtin::*;
|
||||
use deref_into_dyn_supertrait::*;
|
||||
|
|
@ -112,6 +111,7 @@ use pass_by_value::*;
|
|||
use ptr_nulls::*;
|
||||
use redundant_semicolon::*;
|
||||
use reference_casting::*;
|
||||
use shadowed_into_iter::ShadowedIntoIter;
|
||||
use traits::*;
|
||||
use types::*;
|
||||
use unit_bindings::*;
|
||||
|
|
@ -215,7 +215,7 @@ late_lint_methods!(
|
|||
DerefNullPtr: DerefNullPtr,
|
||||
UnstableFeatures: UnstableFeatures,
|
||||
UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
|
||||
ArrayIntoIter: ArrayIntoIter::default(),
|
||||
ShadowedIntoIter: ShadowedIntoIter,
|
||||
DropTraitConstraints: DropTraitConstraints,
|
||||
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
|
||||
NonPanicFmt: NonPanicFmt,
|
||||
|
|
|
|||
|
|
@ -5,16 +5,22 @@ use std::num::NonZero;
|
|||
use crate::errors::RequestedLevel;
|
||||
use crate::fluent_generated as fluent;
|
||||
use rustc_errors::{
|
||||
codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee,
|
||||
LintDiagnostic, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
|
||||
codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString,
|
||||
ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp,
|
||||
Subdiagnostic, SuggestionStyle,
|
||||
};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{def::Namespace, def_id::DefId};
|
||||
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{
|
||||
inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
|
||||
use rustc_session::{lint::AmbiguityErrorDiag, Session};
|
||||
use rustc_span::{
|
||||
edition::Edition,
|
||||
sym,
|
||||
symbol::{Ident, MacroRulesNormalizedIdent},
|
||||
Span, Symbol,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext,
|
||||
|
|
@ -22,17 +28,18 @@ use crate::{
|
|||
|
||||
// array_into_iter.rs
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_array_into_iter)]
|
||||
pub struct ArrayIntoIterDiag<'a> {
|
||||
pub target: &'a str,
|
||||
#[diag(lint_shadowed_into_iter)]
|
||||
pub struct ShadowedIntoIterDiag {
|
||||
pub target: &'static str,
|
||||
pub edition: &'static str,
|
||||
#[suggestion(lint_use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<ArrayIntoIterDiagSub>,
|
||||
pub sub: Option<ShadowedIntoIterDiagSub>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ArrayIntoIterDiagSub {
|
||||
pub enum ShadowedIntoIterDiagSub {
|
||||
#[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
|
||||
RemoveIntoIter {
|
||||
#[primary_span]
|
||||
|
|
@ -1946,3 +1953,837 @@ pub struct UnitBindingsDiag {
|
|||
#[label]
|
||||
pub label: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_builtin_asm_labels)]
|
||||
#[help]
|
||||
#[note]
|
||||
pub struct BuiltinNamedAsmLabel;
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(lint_unexpected_cfg_add_cargo_feature)]
|
||||
#[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
|
||||
#[help(lint_unexpected_cfg_add_build_rs_println)]
|
||||
pub struct UnexpectedCfgCargoHelp {
|
||||
pub build_rs_println: String,
|
||||
pub cargo_toml_lint_cfg: String,
|
||||
}
|
||||
|
||||
impl UnexpectedCfgCargoHelp {
|
||||
pub fn new(unescaped: &str, escaped: &str) -> Self {
|
||||
Self {
|
||||
cargo_toml_lint_cfg: format!(
|
||||
"\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}",
|
||||
),
|
||||
build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");",),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(lint_unexpected_cfg_add_cmdline_arg)]
|
||||
pub struct UnexpectedCfgRustcHelp {
|
||||
pub cmdline_arg: String,
|
||||
}
|
||||
|
||||
impl UnexpectedCfgRustcHelp {
|
||||
pub fn new(unescaped: &str) -> Self {
|
||||
Self { cmdline_arg: format!("--check-cfg={unescaped}") }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unexpected_cfg_name)]
|
||||
pub struct UnexpectedCfgName {
|
||||
#[subdiagnostic]
|
||||
pub code_sugg: unexpected_cfg_name::CodeSuggestion,
|
||||
#[subdiagnostic]
|
||||
pub invocation_help: unexpected_cfg_name::InvocationHelp,
|
||||
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
pub mod unexpected_cfg_name {
|
||||
use rustc_errors::DiagSymbolList;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum CodeSuggestion {
|
||||
#[help(lint_unexpected_cfg_define_features)]
|
||||
DefineFeatures,
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_name_similar_name_value,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameAndValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_name_similar_name_no_value,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameNoValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
},
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_name_similar_name_different_values,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarNameDifferentValues {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
#[subdiagnostic]
|
||||
expected: Option<ExpectedValues>,
|
||||
},
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_name_similar_name,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
SimilarName {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
code: String,
|
||||
#[subdiagnostic]
|
||||
expected: Option<ExpectedValues>,
|
||||
},
|
||||
SimilarValues {
|
||||
#[subdiagnostic]
|
||||
with_similar_values: Vec<FoundWithSimilarValue>,
|
||||
#[subdiagnostic]
|
||||
expected_names: Option<ExpectedNames>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help(lint_unexpected_cfg_name_expected_values)]
|
||||
pub struct ExpectedValues {
|
||||
pub best_match: Symbol,
|
||||
pub possibilities: DiagSymbolList,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_name_with_similar_value,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{code}"
|
||||
)]
|
||||
pub struct FoundWithSimilarValue {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub code: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[help_once(lint_unexpected_cfg_name_expected_names)]
|
||||
pub struct ExpectedNames {
|
||||
pub possibilities: DiagSymbolList,
|
||||
pub and_more: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum InvocationHelp {
|
||||
#[note(lint_unexpected_cfg_doc_cargo)]
|
||||
Cargo {
|
||||
#[subdiagnostic]
|
||||
sub: Option<super::UnexpectedCfgCargoHelp>,
|
||||
},
|
||||
#[note(lint_unexpected_cfg_doc_rustc)]
|
||||
Rustc(#[subdiagnostic] super::UnexpectedCfgRustcHelp),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unexpected_cfg_value)]
|
||||
pub struct UnexpectedCfgValue {
|
||||
#[subdiagnostic]
|
||||
pub code_sugg: unexpected_cfg_value::CodeSuggestion,
|
||||
#[subdiagnostic]
|
||||
pub invocation_help: unexpected_cfg_value::InvocationHelp,
|
||||
|
||||
pub has_value: bool,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
pub mod unexpected_cfg_value {
|
||||
use rustc_errors::DiagSymbolList;
|
||||
use rustc_macros::Subdiagnostic;
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum CodeSuggestion {
|
||||
ChangeValue {
|
||||
#[subdiagnostic]
|
||||
expected_values: ExpectedValues,
|
||||
#[subdiagnostic]
|
||||
suggestion: Option<ChangeValueSuggestion>,
|
||||
},
|
||||
#[note(lint_unexpected_cfg_value_no_expected_value)]
|
||||
RemoveValue {
|
||||
#[subdiagnostic]
|
||||
suggestion: Option<RemoveValueSuggestion>,
|
||||
|
||||
name: Symbol,
|
||||
},
|
||||
#[note(lint_unexpected_cfg_value_no_expected_values)]
|
||||
RemoveCondition {
|
||||
#[subdiagnostic]
|
||||
suggestion: RemoveConditionSuggestion,
|
||||
|
||||
name: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum ChangeValueSuggestion {
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_value_similar_name,
|
||||
code = r#""{best_match}""#,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
SimilarName {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
best_match: Symbol,
|
||||
},
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_value_specify_value,
|
||||
code = r#" = "{first_possibility}""#,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
SpecifyValue {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
first_possibility: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_value_remove_value,
|
||||
code = "",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub struct RemoveValueSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
lint_unexpected_cfg_value_remove_condition,
|
||||
code = "",
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub struct RemoveConditionSuggestion {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_unexpected_cfg_value_expected_values)]
|
||||
pub struct ExpectedValues {
|
||||
pub name: Symbol,
|
||||
pub have_none_possibility: bool,
|
||||
pub possibilities: DiagSymbolList,
|
||||
pub and_more: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum InvocationHelp {
|
||||
#[note(lint_unexpected_cfg_doc_cargo)]
|
||||
Cargo(#[subdiagnostic] Option<CargoHelp>),
|
||||
#[note(lint_unexpected_cfg_doc_rustc)]
|
||||
Rustc(#[subdiagnostic] Option<super::UnexpectedCfgRustcHelp>),
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum CargoHelp {
|
||||
#[help(lint_unexpected_cfg_value_add_feature)]
|
||||
AddFeature {
|
||||
value: Symbol,
|
||||
},
|
||||
#[help(lint_unexpected_cfg_define_features)]
|
||||
DefineFeatures,
|
||||
Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_macro_use_deprecated)]
|
||||
pub struct MacroUseDeprecated;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_macro_use)]
|
||||
pub struct UnusedMacroUse;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_private_extern_crate_reexport)]
|
||||
pub struct PrivateExternCrateReexport {
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_label)]
|
||||
pub struct UnusedLabel;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_macro_is_private)]
|
||||
pub struct MacroIsPrivate {
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_macro_definition)]
|
||||
pub struct UnusedMacroDefinition {
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_macro_rule_never_used)]
|
||||
pub struct MacroRuleNeverUsed {
|
||||
pub n: usize,
|
||||
pub name: Symbol,
|
||||
}
|
||||
|
||||
pub struct UnstableFeature {
|
||||
pub msg: DiagMessage,
|
||||
}
|
||||
|
||||
impl<'a> LintDiagnostic<'a, ()> for UnstableFeature {
|
||||
fn decorate_lint<'b>(self, _diag: &'b mut Diag<'a, ()>) {}
|
||||
|
||||
fn msg(&self) -> DiagMessage {
|
||||
self.msg.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_avoid_intel_syntax)]
|
||||
pub struct AvoidIntelSyntax;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_avoid_att_syntax)]
|
||||
pub struct AvoidAttSyntax;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_incomplete_include)]
|
||||
pub struct IncompleteInclude;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unnameable_test_items)]
|
||||
pub struct UnnameableTestItems;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_duplicate_macro_attribute)]
|
||||
pub struct DuplicateMacroAttribute;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_cfg_attr_no_attributes)]
|
||||
pub struct CfgAttrNoAttributes;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_crate_type_in_cfg_attr_deprecated)]
|
||||
pub struct CrateTypeInCfgAttr;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_crate_name_in_cfg_attr_deprecated)]
|
||||
pub struct CrateNameInCfgAttr;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_missing_fragment_specifier)]
|
||||
pub struct MissingFragmentSpecifier;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_metavariable_still_repeating)]
|
||||
pub struct MetaVariableStillRepeating {
|
||||
pub name: MacroRulesNormalizedIdent,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_metavariable_wrong_operator)]
|
||||
pub struct MetaVariableWrongOperator;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_duplicate_matcher_binding)]
|
||||
pub struct DuplicateMatcherBinding;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unknown_macro_variable)]
|
||||
pub struct UnknownMacroVariable {
|
||||
pub name: MacroRulesNormalizedIdent,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_crate_dependency)]
|
||||
pub struct UnusedCrateDependency {
|
||||
pub extern_crate: Symbol,
|
||||
pub local_crate: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_wasm_c_abi)]
|
||||
pub struct WasmCAbi;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_ill_formed_attribute_input)]
|
||||
pub struct IllFormedAttributeInput {
|
||||
pub num_suggestions: usize,
|
||||
pub suggestions: DiagArgValue,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum InnerAttributeUnstable {
|
||||
#[diag(lint_inner_macro_attribute_unstable)]
|
||||
InnerMacroAttribute,
|
||||
#[diag(lint_custom_inner_attribute_unstable)]
|
||||
CustomInnerAttribute,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unknown_diagnostic_attribute)]
|
||||
pub struct UnknownDiagnosticAttribute {
|
||||
#[subdiagnostic]
|
||||
pub typo: Option<UnknownDiagnosticAttributeTypoSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
lint_unknown_diagnostic_attribute_typo_sugg,
|
||||
style = "verbose",
|
||||
code = "{typo_name}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub struct UnknownDiagnosticAttributeTypoSugg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub typo_name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unicode_text_flow)]
|
||||
#[note]
|
||||
pub struct UnicodeTextFlow {
|
||||
#[label]
|
||||
pub comment_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub characters: Vec<UnicodeCharNoteSub>,
|
||||
#[subdiagnostic]
|
||||
pub suggestions: Option<UnicodeTextFlowSuggestion>,
|
||||
|
||||
pub num_codepoints: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(lint_label_comment_char)]
|
||||
pub struct UnicodeCharNoteSub {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub c_debug: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable", style = "hidden")]
|
||||
pub struct UnicodeTextFlowSuggestion {
|
||||
#[suggestion_part(code = "")]
|
||||
pub spans: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_abs_path_with_module)]
|
||||
pub struct AbsPathWithModule {
|
||||
#[subdiagnostic]
|
||||
pub sugg: AbsPathWithModuleSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(lint_suggestion, code = "{replacement}")]
|
||||
pub struct AbsPathWithModuleSugg {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[applicability]
|
||||
pub applicability: Applicability,
|
||||
pub replacement: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_proc_macro_derive_resolution_fallback)]
|
||||
pub struct ProcMacroDeriveResolutionFallback {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub ns: Namespace,
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_macro_expanded_macro_exports_accessed_by_absolute_paths)]
|
||||
pub struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
|
||||
#[note]
|
||||
pub definition: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_hidden_lifetime_parameters)]
|
||||
pub struct ElidedLifetimesInPaths {
|
||||
#[subdiagnostic]
|
||||
pub subdiag: ElidedLifetimeInPathSubdiag,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_invalid_crate_type_value)]
|
||||
pub struct UnknownCrateTypes {
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<UnknownCrateTypesSub>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(lint_suggestion, code = r#""{candidate}""#, applicability = "maybe-incorrect")]
|
||||
pub struct UnknownCrateTypesSub {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub candidate: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_imports)]
|
||||
pub struct UnusedImports {
|
||||
#[subdiagnostic]
|
||||
pub sugg: UnusedImportsSugg,
|
||||
#[help]
|
||||
pub test_module_span: Option<Span>,
|
||||
|
||||
pub span_snippets: DiagArgValue,
|
||||
pub num_snippets: usize,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum UnusedImportsSugg {
|
||||
#[suggestion(
|
||||
lint_suggestion_remove_whole_use,
|
||||
applicability = "machine-applicable",
|
||||
code = "",
|
||||
style = "tool-only"
|
||||
)]
|
||||
RemoveWholeUse {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[multipart_suggestion(
|
||||
lint_suggestion_remove_imports,
|
||||
applicability = "machine-applicable",
|
||||
style = "tool-only"
|
||||
)]
|
||||
RemoveImports {
|
||||
#[suggestion_part(code = "")]
|
||||
remove_spans: Vec<Span>,
|
||||
num_to_remove: usize,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_redundant_import)]
|
||||
pub struct RedundantImport {
|
||||
#[subdiagnostic]
|
||||
pub subs: Vec<RedundantImportSub>,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum RedundantImportSub {
|
||||
#[label(lint_label_imported_here)]
|
||||
ImportedHere(#[primary_span] Span),
|
||||
#[label(lint_label_defined_here)]
|
||||
DefinedHere(#[primary_span] Span),
|
||||
#[label(lint_label_imported_prelude)]
|
||||
ImportedPrelude(#[primary_span] Span),
|
||||
#[label(lint_label_defined_prelude)]
|
||||
DefinedPrelude(#[primary_span] Span),
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_doc_comment)]
|
||||
#[help]
|
||||
pub struct UnusedDocComment {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
pub enum PatternsInFnsWithoutBody {
|
||||
#[diag(lint_pattern_in_foreign)]
|
||||
Foreign {
|
||||
#[subdiagnostic]
|
||||
sub: PatternsInFnsWithoutBodySub,
|
||||
},
|
||||
#[diag(lint_pattern_in_bodiless)]
|
||||
Bodiless {
|
||||
#[subdiagnostic]
|
||||
sub: PatternsInFnsWithoutBodySub,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(lint_remove_mut_from_pattern, code = "{ident}", applicability = "machine-applicable")]
|
||||
pub struct PatternsInFnsWithoutBodySub {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_extern_without_abi)]
|
||||
#[help]
|
||||
pub struct MissingAbi {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
|
||||
pub default_abi: &'static str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_legacy_derive_helpers)]
|
||||
pub struct LegacyDeriveHelpers {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_proc_macro_back_compat)]
|
||||
#[note]
|
||||
pub struct ProcMacroBackCompat {
|
||||
pub crate_name: String,
|
||||
pub fixed_version: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_or_patterns_back_compat)]
|
||||
pub struct OrPatternsBackCompat {
|
||||
#[suggestion(code = "{suggestion}", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
pub suggestion: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_reserved_prefix)]
|
||||
pub struct ReservedPrefix {
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[suggestion(code = " ", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
|
||||
pub prefix: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_builtin_attribute)]
|
||||
pub struct UnusedBuiltinAttribute {
|
||||
#[note]
|
||||
pub invoc_span: Span,
|
||||
|
||||
pub attr_name: Symbol,
|
||||
pub macro_name: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_trailing_semi_macro)]
|
||||
pub struct TrailingMacro {
|
||||
#[note(lint_note1)]
|
||||
#[note(lint_note2)]
|
||||
pub is_trailing: bool,
|
||||
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_break_with_label_and_loop)]
|
||||
pub struct BreakWithLabelAndLoop {
|
||||
#[subdiagnostic]
|
||||
pub sub: BreakWithLabelAndLoopSub,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
|
||||
pub struct BreakWithLabelAndLoopSub {
|
||||
#[suggestion_part(code = "(")]
|
||||
pub left: Span,
|
||||
#[suggestion_part(code = ")")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_deprecated_where_clause_location)]
|
||||
#[note]
|
||||
pub struct DeprecatedWhereClauseLocation {
|
||||
#[subdiagnostic]
|
||||
pub suggestion: DeprecatedWhereClauseLocationSugg,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum DeprecatedWhereClauseLocationSugg {
|
||||
#[multipart_suggestion(lint_suggestion_move_to_end, applicability = "machine-applicable")]
|
||||
MoveToEnd {
|
||||
#[suggestion_part(code = "")]
|
||||
left: Span,
|
||||
#[suggestion_part(code = "{sugg}")]
|
||||
right: Span,
|
||||
|
||||
sugg: String,
|
||||
},
|
||||
#[suggestion(lint_suggestion_remove_where, code = "", applicability = "machine-applicable")]
|
||||
RemoveWhere {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_single_use_lifetime)]
|
||||
pub struct SingleUseLifetime {
|
||||
#[label(lint_label_param)]
|
||||
pub param_span: Span,
|
||||
#[label(lint_label_use)]
|
||||
pub use_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<SingleUseLifetimeSugg>,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
|
||||
pub struct SingleUseLifetimeSugg {
|
||||
#[suggestion_part(code = "")]
|
||||
pub deletion_span: Option<Span>,
|
||||
#[suggestion_part(code = "{replace_lt}")]
|
||||
pub use_span: Span,
|
||||
|
||||
pub replace_lt: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_lifetime)]
|
||||
pub struct UnusedLifetime {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub deletion_span: Option<Span>,
|
||||
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_named_argument_used_positionally)]
|
||||
pub struct NamedArgumentUsedPositionally {
|
||||
#[label(lint_label_named_arg)]
|
||||
pub named_arg_sp: Span,
|
||||
#[label(lint_label_position_arg)]
|
||||
pub position_label_sp: Option<Span>,
|
||||
#[suggestion(style = "verbose", code = "{name}", applicability = "maybe-incorrect")]
|
||||
pub suggestion: Option<Span>,
|
||||
|
||||
pub name: String,
|
||||
pub named_arg_name: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_byte_slice_in_packed_struct_with_derive)]
|
||||
#[help]
|
||||
pub struct ByteSliceInPackedStructWithDerive {
|
||||
// FIXME: make this translatable
|
||||
pub ty: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_extern_crate)]
|
||||
pub struct UnusedExternCrate {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub removal_span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_extern_crate_not_idiomatic)]
|
||||
pub struct ExternCrateNotIdiomatic {
|
||||
#[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
|
||||
pub code: &'static str,
|
||||
}
|
||||
|
||||
// FIXME: make this translatable
|
||||
pub struct AmbiguousGlobImports {
|
||||
pub ambiguity: AmbiguityErrorDiag,
|
||||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports {
|
||||
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
|
||||
rustc_errors::report_ambiguity_error(diag, self.ambiguity);
|
||||
}
|
||||
|
||||
fn msg(&self) -> DiagMessage {
|
||||
DiagMessage::Str(self.ambiguity.msg.clone().into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_ambiguous_glob_reexport)]
|
||||
pub struct AmbiguousGlobReexports {
|
||||
#[label(lint_label_first_reexport)]
|
||||
pub first_reexport: Span,
|
||||
#[label(lint_label_duplicate_reexport)]
|
||||
pub duplicate_reexport: Span,
|
||||
|
||||
pub name: String,
|
||||
// FIXME: make this translatable
|
||||
pub namespace: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_hidden_glob_reexport)]
|
||||
pub struct HiddenGlobReexports {
|
||||
#[note(lint_note_glob_reexport)]
|
||||
pub glob_reexport: Span,
|
||||
#[note(lint_note_private_item)]
|
||||
pub private_item: Span,
|
||||
|
||||
pub name: String,
|
||||
// FIXME: make this translatable
|
||||
pub namespace: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unnecessary_qualification)]
|
||||
pub struct UnusedQualifications {
|
||||
#[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
|
||||
pub removal_span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_associated_const_elided_lifetime)]
|
||||
pub struct AssociatedConstElidedLifetime {
|
||||
#[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
|
||||
pub code: &'static str,
|
||||
pub elided: bool,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_redundant_import_visibility)]
|
||||
pub struct RedundantImportVisibility {
|
||||
#[note]
|
||||
pub span: Span,
|
||||
#[help]
|
||||
pub help: (),
|
||||
|
||||
pub import_vis: String,
|
||||
pub max_vis: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ declare_lint! {
|
|||
///
|
||||
/// Creating non-local definitions go against expectation and can create discrepancies
|
||||
/// in tooling. It should be avoided. It may become deny-by-default in edition 2024
|
||||
/// and higher, see see the tracking issue <https://github.com/rust-lang/rust/issues/120363>.
|
||||
/// and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>.
|
||||
///
|
||||
/// An `impl` definition is non-local if it is nested inside an item and neither
|
||||
/// the type nor the trait are at the same nesting level as the `impl` block.
|
||||
|
|
|
|||
157
compiler/rustc_lint/src/shadowed_into_iter.rs
Normal file
157
compiler/rustc_lint/src/shadowed_into_iter.rs
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
use crate::lints::{ShadowedIntoIterDiag, ShadowedIntoIterDiagSub};
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::edition::Edition;
|
||||
|
||||
declare_lint! {
|
||||
/// The `array_into_iter` lint detects calling `into_iter` on arrays.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,edition2018
|
||||
/// # #![allow(unused)]
|
||||
/// [1, 2, 3].into_iter().for_each(|n| { *n; });
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
|
||||
/// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
|
||||
/// behave as `(&array).into_iter()`, returning an iterator over
|
||||
/// references, just like in Rust 1.52 and earlier.
|
||||
/// This only applies to the method call syntax `array.into_iter()`, not to
|
||||
/// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
|
||||
pub ARRAY_INTO_ITER,
|
||||
Warn,
|
||||
"detects calling `into_iter` on arrays in Rust 2015 and 2018",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
|
||||
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `boxed_slice_into_iter` lint detects calling `into_iter` on boxed slices.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,edition2021
|
||||
/// # #![allow(unused)]
|
||||
/// vec![1, 2, 3].into_boxed_slice().into_iter().for_each(|n| { *n; });
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Since Rust CURRENT_RUSTC_VERSION, boxed slices implement `IntoIterator`. However, to avoid
|
||||
/// breakage, `boxed_slice.into_iter()` in Rust 2015, 2018, and 2021 code will still
|
||||
/// behave as `(&boxed_slice).into_iter()`, returning an iterator over
|
||||
/// references, just like in Rust CURRENT_RUSTC_VERSION and earlier.
|
||||
/// This only applies to the method call syntax `boxed_slice.into_iter()`, not to
|
||||
/// any other syntax such as `for _ in boxed_slice` or `IntoIterator::into_iter(boxed_slice)`.
|
||||
pub BOXED_SLICE_INTO_ITER,
|
||||
Warn,
|
||||
"detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ShadowedIntoIter;
|
||||
|
||||
impl_lint_pass!(ShadowedIntoIter => [ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Check if the method call actually calls the libcore
|
||||
// `IntoIterator::into_iter`.
|
||||
let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
|
||||
return;
|
||||
};
|
||||
if Some(method_def_id) != cx.tcx.lang_items().into_iter_fn() {
|
||||
return;
|
||||
}
|
||||
|
||||
// As this is a method call expression, we have at least one argument.
|
||||
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
|
||||
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
|
||||
|
||||
let adjusted_receiver_tys: Vec<_> =
|
||||
[receiver_ty].into_iter().chain(adjustments.iter().map(|adj| adj.target)).collect();
|
||||
|
||||
fn is_ref_to_array(ty: Ty<'_>) -> bool {
|
||||
if let ty::Ref(_, pointee_ty, _) = *ty.kind() { pointee_ty.is_array() } else { false }
|
||||
}
|
||||
fn is_boxed_slice(ty: Ty<'_>) -> bool {
|
||||
ty.is_box() && ty.boxed_ty().is_slice()
|
||||
}
|
||||
fn is_ref_to_boxed_slice(ty: Ty<'_>) -> bool {
|
||||
if let ty::Ref(_, pointee_ty, _) = *ty.kind() {
|
||||
is_boxed_slice(pointee_ty)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
let (lint, target, edition, can_suggest_ufcs) =
|
||||
if is_ref_to_array(*adjusted_receiver_tys.last().unwrap())
|
||||
&& let Some(idx) = adjusted_receiver_tys
|
||||
.iter()
|
||||
.copied()
|
||||
.take_while(|ty| !is_ref_to_array(*ty))
|
||||
.position(|ty| ty.is_array())
|
||||
{
|
||||
(ARRAY_INTO_ITER, "[T; N]", "2021", idx == 0)
|
||||
} else if is_ref_to_boxed_slice(*adjusted_receiver_tys.last().unwrap())
|
||||
&& let Some(idx) = adjusted_receiver_tys
|
||||
.iter()
|
||||
.copied()
|
||||
.take_while(|ty| !is_ref_to_boxed_slice(*ty))
|
||||
.position(|ty| is_boxed_slice(ty))
|
||||
{
|
||||
(BOXED_SLICE_INTO_ITER, "Box<[T]>", "2024", idx == 0)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
// If this expression comes from the `IntoIter::into_iter` inside of a for loop,
|
||||
// we should just suggest removing the `.into_iter()` or changing it to `.iter()`
|
||||
// to disambiguate if we want to iterate by-value or by-ref.
|
||||
let sub = if let Some((_, hir::Node::Expr(parent_expr))) =
|
||||
cx.tcx.hir().parent_iter(expr.hir_id).nth(1)
|
||||
&& let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) =
|
||||
&parent_expr.kind
|
||||
&& let hir::ExprKind::Call(path, [_]) = &arg.kind
|
||||
&& let hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoIterIntoIter, ..)) =
|
||||
&path.kind
|
||||
{
|
||||
Some(ShadowedIntoIterDiagSub::RemoveIntoIter {
|
||||
span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
})
|
||||
} else if can_suggest_ufcs {
|
||||
Some(ShadowedIntoIterDiagSub::UseExplicitIntoIter {
|
||||
start_span: expr.span.shrink_to_lo(),
|
||||
end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
cx.emit_span_lint(
|
||||
lint,
|
||||
call.ident.span,
|
||||
ShadowedIntoIterDiag { target, edition, suggestion: call.ident.span, sub },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -3339,11 +3339,14 @@ declare_lint! {
|
|||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This lint is only active when `--check-cfg` arguments are being passed
|
||||
/// to the compiler and triggers whenever an unexpected condition name or value is used.
|
||||
/// This lint is only active when [`--check-cfg`][check-cfg] arguments are being
|
||||
/// passed to the compiler and triggers whenever an unexpected condition name or value is
|
||||
/// used.
|
||||
///
|
||||
/// The known condition include names or values passed in `--check-cfg`, and some
|
||||
/// well-knows names and values built into the compiler.
|
||||
/// See the [Checking Conditional Configurations][check-cfg] section for more
|
||||
/// details.
|
||||
///
|
||||
/// [check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
|
||||
pub UNEXPECTED_CFGS,
|
||||
Warn,
|
||||
"detects unexpected names and values in `#[cfg]` conditions",
|
||||
|
|
@ -4263,8 +4266,7 @@ declare_lint! {
|
|||
///
|
||||
/// // where absurd is a function with the following signature
|
||||
/// // (it's sound, because `!` always marks unreachable code):
|
||||
/// fn absurd<T>(_: !) -> T { ... }
|
||||
// FIXME: use `core::convert::absurd` here instead, once it's merged
|
||||
/// fn absurd<T>(never: !) -> T { ... }
|
||||
/// ```
|
||||
///
|
||||
/// While it's convenient to be able to use non-diverging code in one of the branches (like
|
||||
|
|
@ -4321,7 +4323,12 @@ declare_lint! {
|
|||
/// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html
|
||||
pub NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
|
||||
Warn,
|
||||
"never type fallback affecting unsafe function calls"
|
||||
"never type fallback affecting unsafe function calls",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
|
||||
reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
|
||||
};
|
||||
report_in_external_macro
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,12 @@ use rustc_data_structures::stable_hasher::{
|
|||
HashStable, StableCompare, StableHasher, ToStableHashKey,
|
||||
};
|
||||
use rustc_error_messages::{DiagMessage, MultiSpan};
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::HashStableContext;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::symbol::MacroRulesNormalizedIdent;
|
||||
use rustc_span::{sym, symbol::Ident, Span, Symbol};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
|
|
@ -565,19 +567,44 @@ pub struct AmbiguityErrorDiag {
|
|||
pub b2_help_msgs: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DeprecatedSinceKind {
|
||||
InEffect,
|
||||
InFuture,
|
||||
InVersion(String),
|
||||
}
|
||||
|
||||
// This could be a closure, but then implementing derive trait
|
||||
// becomes hacky (and it gets allocated).
|
||||
#[derive(Debug)]
|
||||
pub enum BuiltinLintDiag {
|
||||
Normal,
|
||||
AbsPathWithModule(Span),
|
||||
ProcMacroDeriveResolutionFallback(Span),
|
||||
ProcMacroDeriveResolutionFallback {
|
||||
span: Span,
|
||||
ns: Namespace,
|
||||
ident: Ident,
|
||||
},
|
||||
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
|
||||
ElidedLifetimesInPaths(usize, Span, bool, Span),
|
||||
UnknownCrateTypes(Span, String, String),
|
||||
UnusedImports(String, Vec<(Span, String)>, Option<Span>),
|
||||
UnknownCrateTypes {
|
||||
span: Span,
|
||||
candidate: Option<Symbol>,
|
||||
},
|
||||
UnusedImports {
|
||||
remove_whole_use: bool,
|
||||
num_to_remove: usize,
|
||||
remove_spans: Vec<Span>,
|
||||
test_module_span: Option<Span>,
|
||||
span_snippets: Vec<String>,
|
||||
},
|
||||
RedundantImport(Vec<(Span, bool)>, Ident),
|
||||
DeprecatedMacro(Option<Symbol>, Span),
|
||||
DeprecatedMacro {
|
||||
suggestion: Option<Symbol>,
|
||||
suggestion_span: Span,
|
||||
note: Option<Symbol>,
|
||||
path: String,
|
||||
since_kind: DeprecatedSinceKind,
|
||||
},
|
||||
MissingAbi(Span, Abi),
|
||||
UnusedDocComment(Span),
|
||||
UnusedBuiltinAttribute {
|
||||
|
|
@ -585,18 +612,24 @@ pub enum BuiltinLintDiag {
|
|||
macro_name: String,
|
||||
invoc_span: Span,
|
||||
},
|
||||
PatternsInFnsWithoutBody(Span, Ident),
|
||||
PatternsInFnsWithoutBody {
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
is_foreign: bool,
|
||||
},
|
||||
LegacyDeriveHelpers(Span),
|
||||
ProcMacroBackCompat(String),
|
||||
ProcMacroBackCompat {
|
||||
crate_name: String,
|
||||
fixed_version: String,
|
||||
},
|
||||
OrPatternsBackCompat(Span, String),
|
||||
ReservedPrefix(Span),
|
||||
ReservedPrefix(Span, String),
|
||||
TrailingMacro(bool, Ident),
|
||||
BreakWithLabelAndLoop(Span),
|
||||
NamedAsmLabel(String),
|
||||
UnicodeTextFlow(Span, String),
|
||||
UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
|
||||
UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
|
||||
DeprecatedWhereclauseLocation(Option<(Span, String)>),
|
||||
DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
|
||||
SingleUseLifetime {
|
||||
/// Span of the parameter which declares this lifetime.
|
||||
param_span: Span,
|
||||
|
|
@ -606,6 +639,7 @@ pub enum BuiltinLintDiag {
|
|||
/// Span of the single use, or None if the lifetime is never used.
|
||||
/// If true, the lifetime will be fully elided.
|
||||
use_span: Option<(Span, bool)>,
|
||||
ident: Ident,
|
||||
},
|
||||
NamedArgumentUsedPositionally {
|
||||
/// Span where the named argument is used by position and will be replaced with the named
|
||||
|
|
@ -620,7 +654,10 @@ pub enum BuiltinLintDiag {
|
|||
/// Indicates if the named argument is used as a width/precision for formatting
|
||||
is_formatting_arg: bool,
|
||||
},
|
||||
ByteSliceInPackedStructWithDerive,
|
||||
ByteSliceInPackedStructWithDerive {
|
||||
// FIXME: enum of byte/string
|
||||
ty: String,
|
||||
},
|
||||
UnusedExternCrate {
|
||||
removal_span: Span,
|
||||
},
|
||||
|
|
@ -662,10 +699,43 @@ pub enum BuiltinLintDiag {
|
|||
RedundantImportVisibility {
|
||||
span: Span,
|
||||
max_vis: String,
|
||||
import_vis: String,
|
||||
},
|
||||
MaybeTypo {
|
||||
UnknownDiagnosticAttribute {
|
||||
span: Span,
|
||||
name: Symbol,
|
||||
typo_name: Option<Symbol>,
|
||||
},
|
||||
MacroUseDeprecated,
|
||||
UnusedMacroUse,
|
||||
PrivateExternCrateReexport(Ident),
|
||||
UnusedLabel,
|
||||
MacroIsPrivate(Ident),
|
||||
UnusedMacroDefinition(Symbol),
|
||||
MacroRuleNeverUsed(usize, Symbol),
|
||||
UnstableFeature(DiagMessage),
|
||||
AvoidUsingIntelSyntax,
|
||||
AvoidUsingAttSyntax,
|
||||
IncompleteInclude,
|
||||
UnnameableTestItems,
|
||||
DuplicateMacroAttribute,
|
||||
CfgAttrNoAttributes,
|
||||
CrateTypeInCfgAttr,
|
||||
CrateNameInCfgAttr,
|
||||
MissingFragmentSpecifier,
|
||||
MetaVariableStillRepeating(MacroRulesNormalizedIdent),
|
||||
MetaVariableWrongOperator,
|
||||
DuplicateMatcherBinding,
|
||||
UnknownMacroVariable(MacroRulesNormalizedIdent),
|
||||
UnusedCrateDependency {
|
||||
extern_crate: Symbol,
|
||||
local_crate: Symbol,
|
||||
},
|
||||
WasmCAbi,
|
||||
IllFormedAttributeInput {
|
||||
suggestions: Vec<String>,
|
||||
},
|
||||
InnerAttributeUnstable {
|
||||
is_macro: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -676,9 +746,6 @@ pub struct BufferedEarlyLint {
|
|||
/// The span of code that we are linting on.
|
||||
pub span: MultiSpan,
|
||||
|
||||
/// The lint message.
|
||||
pub msg: DiagMessage,
|
||||
|
||||
/// The `NodeId` of the AST node that generated the lint.
|
||||
pub node_id: NodeId,
|
||||
|
||||
|
|
@ -706,12 +773,10 @@ impl LintBuffer {
|
|||
lint: &'static Lint,
|
||||
node_id: NodeId,
|
||||
span: MultiSpan,
|
||||
msg: impl Into<DiagMessage>,
|
||||
diagnostic: BuiltinLintDiag,
|
||||
) {
|
||||
let lint_id = LintId::of(lint);
|
||||
let msg = msg.into();
|
||||
self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
|
||||
self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, diagnostic });
|
||||
}
|
||||
|
||||
pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
|
||||
|
|
@ -724,20 +789,9 @@ impl LintBuffer {
|
|||
lint: &'static Lint,
|
||||
id: NodeId,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
) {
|
||||
self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiag::Normal)
|
||||
}
|
||||
|
||||
pub fn buffer_lint_with_diagnostic(
|
||||
&mut self,
|
||||
lint: &'static Lint,
|
||||
id: NodeId,
|
||||
sp: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagMessage>,
|
||||
diagnostic: BuiltinLintDiag,
|
||||
) {
|
||||
self.add_lint(lint, id, sp.into(), msg, diagnostic)
|
||||
self.add_lint(lint, id, sp.into(), diagnostic)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,9 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
let slug = subdiag.slug.unwrap_or_else(|| match subdiag.kind {
|
||||
SubdiagnosticKind::Label => parse_quote! { _subdiag::label },
|
||||
SubdiagnosticKind::Note => parse_quote! { _subdiag::note },
|
||||
SubdiagnosticKind::NoteOnce => parse_quote! { _subdiag::note_once },
|
||||
SubdiagnosticKind::Help => parse_quote! { _subdiag::help },
|
||||
SubdiagnosticKind::HelpOnce => parse_quote! { _subdiag::help_once },
|
||||
SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn },
|
||||
SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion },
|
||||
SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
|
||||
|
|
@ -233,9 +235,11 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
};
|
||||
let fn_ident = format_ident!("{}", subdiag);
|
||||
match subdiag {
|
||||
SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
|
||||
Ok(self.add_subdiagnostic(&fn_ident, slug))
|
||||
}
|
||||
SubdiagnosticKind::Note
|
||||
| SubdiagnosticKind::NoteOnce
|
||||
| SubdiagnosticKind::Help
|
||||
| SubdiagnosticKind::HelpOnce
|
||||
| SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, slug)),
|
||||
SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => {
|
||||
throw_invalid_attr!(attr, |diag| diag
|
||||
.help("`#[label]` and `#[suggestion]` can only be applied to fields"));
|
||||
|
|
@ -347,7 +351,11 @@ impl DiagnosticDeriveVariantBuilder {
|
|||
report_error_if_not_applied_to_span(attr, &info)?;
|
||||
Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
|
||||
}
|
||||
SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
|
||||
SubdiagnosticKind::Note
|
||||
| SubdiagnosticKind::NoteOnce
|
||||
| SubdiagnosticKind::Help
|
||||
| SubdiagnosticKind::HelpOnce
|
||||
| SubdiagnosticKind::Warn => {
|
||||
let inner = info.ty.inner_type();
|
||||
if type_matches_path(inner, &["rustc_span", "Span"])
|
||||
|| type_matches_path(inner, &["rustc_span", "MultiSpan"])
|
||||
|
|
|
|||
|
|
@ -510,11 +510,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
|
|||
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
|
||||
.collect();
|
||||
|
||||
if kind_slugs.is_empty() {
|
||||
if kind_slugs.is_empty() && !self.has_subdiagnostic {
|
||||
if self.is_enum {
|
||||
// It's okay for a variant to not be a subdiagnostic at all..
|
||||
return Ok(quote! {});
|
||||
} else if !self.has_subdiagnostic {
|
||||
} else {
|
||||
// ..but structs should always be _something_.
|
||||
throw_span_err!(
|
||||
self.variant.ast().ident.span().unwrap(),
|
||||
|
|
|
|||
|
|
@ -575,8 +575,12 @@ pub(super) enum SubdiagnosticKind {
|
|||
Label,
|
||||
/// `#[note(...)]`
|
||||
Note,
|
||||
/// `#[note_once(...)]`
|
||||
NoteOnce,
|
||||
/// `#[help(...)]`
|
||||
Help,
|
||||
/// `#[help_once(...)]`
|
||||
HelpOnce,
|
||||
/// `#[warning(...)]`
|
||||
Warn,
|
||||
/// `#[suggestion{,_short,_hidden,_verbose}]`
|
||||
|
|
@ -624,7 +628,9 @@ impl SubdiagnosticVariant {
|
|||
let mut kind = match name {
|
||||
"label" => SubdiagnosticKind::Label,
|
||||
"note" => SubdiagnosticKind::Note,
|
||||
"note_once" => SubdiagnosticKind::NoteOnce,
|
||||
"help" => SubdiagnosticKind::Help,
|
||||
"help_once" => SubdiagnosticKind::HelpOnce,
|
||||
"warning" => SubdiagnosticKind::Warn,
|
||||
_ => {
|
||||
// Recover old `#[(multipart_)suggestion_*]` syntaxes
|
||||
|
|
@ -682,7 +688,9 @@ impl SubdiagnosticVariant {
|
|||
match kind {
|
||||
SubdiagnosticKind::Label
|
||||
| SubdiagnosticKind::Note
|
||||
| SubdiagnosticKind::NoteOnce
|
||||
| SubdiagnosticKind::Help
|
||||
| SubdiagnosticKind::HelpOnce
|
||||
| SubdiagnosticKind::Warn
|
||||
| SubdiagnosticKind::MultipartSuggestion { .. } => {
|
||||
return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false }));
|
||||
|
|
@ -836,7 +844,9 @@ impl SubdiagnosticVariant {
|
|||
}
|
||||
SubdiagnosticKind::Label
|
||||
| SubdiagnosticKind::Note
|
||||
| SubdiagnosticKind::NoteOnce
|
||||
| SubdiagnosticKind::Help
|
||||
| SubdiagnosticKind::HelpOnce
|
||||
| SubdiagnosticKind::Warn => {}
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +859,9 @@ impl quote::IdentFragment for SubdiagnosticKind {
|
|||
match self {
|
||||
SubdiagnosticKind::Label => write!(f, "label"),
|
||||
SubdiagnosticKind::Note => write!(f, "note"),
|
||||
SubdiagnosticKind::NoteOnce => write!(f, "note_once"),
|
||||
SubdiagnosticKind::Help => write!(f, "help"),
|
||||
SubdiagnosticKind::HelpOnce => write!(f, "help_once"),
|
||||
SubdiagnosticKind::Warn => write!(f, "warn"),
|
||||
SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"),
|
||||
SubdiagnosticKind::MultipartSuggestion { .. } => {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ decl_derive!(
|
|||
// struct attributes
|
||||
diag,
|
||||
help,
|
||||
help_once,
|
||||
note,
|
||||
note_once,
|
||||
warning,
|
||||
// field attributes
|
||||
skip_arg,
|
||||
|
|
@ -125,7 +127,9 @@ decl_derive!(
|
|||
// struct attributes
|
||||
diag,
|
||||
help,
|
||||
help_once,
|
||||
note,
|
||||
note_once,
|
||||
warning,
|
||||
// field attributes
|
||||
skip_arg,
|
||||
|
|
@ -142,7 +146,9 @@ decl_derive!(
|
|||
// struct/variant attributes
|
||||
label,
|
||||
help,
|
||||
help_once,
|
||||
note,
|
||||
note_once,
|
||||
warning,
|
||||
subdiagnostic,
|
||||
suggestion,
|
||||
|
|
|
|||
|
|
@ -284,8 +284,6 @@ metadata_unsupported_abi =
|
|||
metadata_unsupported_abi_i686 =
|
||||
ABI not supported by `#[link(kind = "raw-dylib")]` on i686
|
||||
|
||||
metadata_wasm_c_abi =
|
||||
older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
|
||||
metadata_wasm_import_form =
|
||||
wasm import module must be of the form `wasm_import_module = "string"`
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use rustc_middle::bug;
|
|||
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
|
||||
use rustc_session::config::{self, CrateType, ExternLocation};
|
||||
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::lint::{self, BuiltinLintDiag};
|
||||
use rustc_session::output::validate_crate_name;
|
||||
use rustc_session::search_paths::PathKind;
|
||||
use rustc_span::edition::Edition;
|
||||
|
|
@ -975,15 +975,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.sess.psess.buffer_lint(
|
||||
lint::builtin::UNUSED_CRATE_DEPENDENCIES,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
format!(
|
||||
"external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`",
|
||||
name,
|
||||
self.tcx.crate_name(LOCAL_CRATE),
|
||||
name),
|
||||
);
|
||||
lint::builtin::UNUSED_CRATE_DEPENDENCIES,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
BuiltinLintDiag::UnusedCrateDependency {
|
||||
extern_crate: name_interned,
|
||||
local_crate: self.tcx.crate_name(LOCAL_CRATE),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1020,7 +1019,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
|
|||
lint::builtin::WASM_C_ABI,
|
||||
span,
|
||||
ast::CRATE_NODE_ID,
|
||||
crate::fluent_generated::metadata_wasm_c_abi,
|
||||
BuiltinLintDiag::WasmCAbi,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![allow(internal_features)]
|
||||
#![feature(coroutines)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(error_iter)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(coroutines)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(trusted_len)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(never_type)]
|
||||
#![allow(rustc::potential_query_instability)]
|
||||
#![feature(proc_macro_internals)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(trusted_len)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
use crate::creader::CrateMetadataRef;
|
||||
use decoder::Metadata;
|
||||
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
|
||||
use decoder::{DecodeContext, Metadata};
|
||||
use def_path_hash_map::DefPathHashMapRef;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::lib_features::FeatureStability;
|
||||
use table::TableBuilder;
|
||||
|
||||
use encoder::EncodeContext;
|
||||
pub use encoder::{encode_metadata, rendered_const, EncodedMetadata};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::expand::StrippedCfgItem;
|
||||
use rustc_attr as attr;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
|
||||
|
|
@ -18,10 +16,13 @@ use rustc_hir::definitions::DefKey;
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
|
||||
use rustc_macros::{MetadataDecodable, MetadataEncodable};
|
||||
use rustc_middle::metadata::ModChild;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
||||
use rustc_middle::middle::lib_features::FeatureStability;
|
||||
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::trivially_parameterized_over_tcx;
|
||||
|
|
@ -33,20 +34,14 @@ use rustc_serialize::opaque::FileEncoder;
|
|||
use rustc_session::config::SymbolManglingVersion;
|
||||
use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::hygiene::{ExpnIndex, MacroKind};
|
||||
use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
|
||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||
use rustc_target::spec::{PanicStrategy, TargetTriple};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZero;
|
||||
|
||||
use decoder::DecodeContext;
|
||||
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
|
||||
use encoder::EncodeContext;
|
||||
pub use encoder::{encode_metadata, rendered_const, EncodedMetadata};
|
||||
use rustc_span::hygiene::SyntaxContextData;
|
||||
use table::TableBuilder;
|
||||
|
||||
mod decoder;
|
||||
mod def_path_hash_map;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,20 @@ middle_const_not_used_in_type_alias =
|
|||
middle_cycle =
|
||||
a cycle occurred during layout computation
|
||||
|
||||
middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note ->
|
||||
[true] : {$note}
|
||||
*[other] {""}
|
||||
}
|
||||
middle_deprecated_in_future = use of {$kind} `{$path}` that will be deprecated in a future Rust version{$has_note ->
|
||||
[true] : {$note}
|
||||
*[other] {""}
|
||||
}
|
||||
middle_deprecated_in_version = use of {$kind} `{$path}` that will be deprecated in future version {$version}{$has_note ->
|
||||
[true] : {$note}
|
||||
*[other] {""}
|
||||
}
|
||||
middle_deprecated_suggestion = replace the use of the deprecated {$kind}
|
||||
|
||||
middle_drop_check_overflow =
|
||||
overflow while adding drop-check rules for {$ty}
|
||||
.note = overflowed on {$overflow_ty}
|
||||
|
|
|
|||
|
|
@ -511,14 +511,14 @@ impl<'hir> Map<'hir> {
|
|||
self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
|
||||
}
|
||||
|
||||
/// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
|
||||
/// `while` or `loop` before reaching it, as block tail returns are not
|
||||
/// available in them.
|
||||
/// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is
|
||||
/// in the "tail" position of the function, in other words if it's likely to correspond
|
||||
/// to the return type of the function.
|
||||
///
|
||||
/// ```
|
||||
/// fn foo(x: usize) -> bool {
|
||||
/// if x == 1 {
|
||||
/// true // If `get_return_block` gets passed the `id` corresponding
|
||||
/// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding
|
||||
/// } else { // to this, it will return `foo`'s `HirId`.
|
||||
/// false
|
||||
/// }
|
||||
|
|
@ -528,12 +528,12 @@ impl<'hir> Map<'hir> {
|
|||
/// ```compile_fail,E0308
|
||||
/// fn foo(x: usize) -> bool {
|
||||
/// loop {
|
||||
/// true // If `get_return_block` gets passed the `id` corresponding
|
||||
/// true // If `get_fn_id_for_return_block` gets passed the `id` corresponding
|
||||
/// } // to this, it will return `None`.
|
||||
/// false
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_return_block(self, id: HirId) -> Option<HirId> {
|
||||
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
|
||||
let mut iter = self.parent_iter(id).peekable();
|
||||
let mut ignore_tail = false;
|
||||
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
|
||||
|
|
@ -549,6 +549,11 @@ impl<'hir> Map<'hir> {
|
|||
Node::Block(Block { expr: None, .. }) => return None,
|
||||
// The current node is not the tail expression of its parent.
|
||||
Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
|
||||
Node::Block(Block { expr: Some(e), .. })
|
||||
if matches!(e.kind, ExprKind::If(_, _, None)) =>
|
||||
{
|
||||
return None;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue