Auto merge of #68142 - Centril:rollup-dl232e9, r=Centril
Rollup of 6 pull requests Successful merges: - #67494 (Constify more of alloc::Layout) - #67867 (Correctly check for opaque types in `assoc_ty_def`) - #67948 (Galloping search for binary_search_util) - #68045 (Move more of `rustc::lint` into `rustc_lint`) - #68089 (Unstabilize `Vec::remove_item`) - #68108 (Add suggestions when encountering chained comparisons) Failed merges: r? @ghost
This commit is contained in:
commit
0b6c116a84
65 changed files with 1404 additions and 1092 deletions
|
@ -3663,6 +3663,7 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"rustc",
|
"rustc",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
|
"rustc_error_codes",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
@ -3788,6 +3789,7 @@ dependencies = [
|
||||||
"rustc_error_codes",
|
"rustc_error_codes",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
|
"rustc_lint",
|
||||||
"rustc_metadata",
|
"rustc_metadata",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"syntax",
|
"syntax",
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(binary_heap_into_iter_sorted)]
|
#![feature(binary_heap_into_iter_sorted)]
|
||||||
#![feature(binary_heap_drain_sorted)]
|
#![feature(binary_heap_drain_sorted)]
|
||||||
|
#![feature(vec_remove_item)]
|
||||||
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
|
@ -1696,13 +1696,14 @@ impl<T> Vec<T> {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
/// # #![feature(vec_remove_item)]
|
||||||
/// let mut vec = vec![1, 2, 3, 1];
|
/// let mut vec = vec![1, 2, 3, 1];
|
||||||
///
|
///
|
||||||
/// vec.remove_item(&1);
|
/// vec.remove_item(&1);
|
||||||
///
|
///
|
||||||
/// assert_eq!(vec, vec![2, 3, 1]);
|
/// assert_eq!(vec, vec![2, 3, 1]);
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "vec_remove_item", since = "1.42.0")]
|
#[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
|
||||||
pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
|
pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
|
||||||
where
|
where
|
||||||
T: PartialEq<V>,
|
T: PartialEq<V>,
|
||||||
|
|
|
@ -64,8 +64,9 @@ impl Layout {
|
||||||
/// must not overflow (i.e., the rounded value must be less than
|
/// must not overflow (i.e., the rounded value must be less than
|
||||||
/// `usize::MAX`).
|
/// `usize::MAX`).
|
||||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
|
pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
|
||||||
if !align.is_power_of_two() {
|
if !align.is_power_of_two() {
|
||||||
return Err(LayoutErr { private: () });
|
return Err(LayoutErr { private: () });
|
||||||
}
|
}
|
||||||
|
@ -106,15 +107,17 @@ impl Layout {
|
||||||
|
|
||||||
/// The minimum size in bytes for a memory block of this layout.
|
/// The minimum size in bytes for a memory block of this layout.
|
||||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> usize {
|
pub const fn size(&self) -> usize {
|
||||||
self.size_
|
self.size_
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The minimum byte alignment for a memory block of this layout.
|
/// The minimum byte alignment for a memory block of this layout.
|
||||||
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
#[stable(feature = "alloc_layout", since = "1.28.0")]
|
||||||
|
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn align(&self) -> usize {
|
pub const fn align(&self) -> usize {
|
||||||
self.align_.get()
|
self.align_.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +184,9 @@ impl Layout {
|
||||||
/// address for the whole allocated block of memory. One way to
|
/// address for the whole allocated block of memory. One way to
|
||||||
/// satisfy this constraint is to ensure `align <= self.align()`.
|
/// satisfy this constraint is to ensure `align <= self.align()`.
|
||||||
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
|
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
|
||||||
|
#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn padding_needed_for(&self, align: usize) -> usize {
|
pub const fn padding_needed_for(&self, align: usize) -> usize {
|
||||||
let len = self.size();
|
let len = self.size();
|
||||||
|
|
||||||
// Rounded up value is:
|
// Rounded up value is:
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
#![feature(bound_cloned)]
|
#![feature(bound_cloned)]
|
||||||
#![feature(cfg_target_has_atomic)]
|
#![feature(cfg_target_has_atomic)]
|
||||||
#![feature(concat_idents)]
|
#![feature(concat_idents)]
|
||||||
|
#![feature(const_alloc_layout)]
|
||||||
#![feature(const_if_match)]
|
#![feature(const_if_match)]
|
||||||
#![feature(const_panic)]
|
#![feature(const_panic)]
|
||||||
#![feature(const_fn_union)]
|
#![feature(const_fn_union)]
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
//! item.
|
//! item.
|
||||||
|
|
||||||
use crate::hir::map::Map;
|
use crate::hir::map::Map;
|
||||||
use crate::lint::builtin::UNUSED_ATTRIBUTES;
|
|
||||||
use crate::ty::query::Providers;
|
use crate::ty::query::Providers;
|
||||||
use crate::ty::TyCtxt;
|
use crate::ty::TyCtxt;
|
||||||
|
|
||||||
|
@ -16,6 +15,7 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
use rustc_hir::DUMMY_HIR_ID;
|
use rustc_hir::DUMMY_HIR_ID;
|
||||||
use rustc_hir::{self, HirId, Item, ItemKind, TraitItem, TraitItemKind};
|
use rustc_hir::{self, HirId, Item, ItemKind, TraitItem, TraitItemKind};
|
||||||
|
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use syntax::ast::Attribute;
|
use syntax::ast::Attribute;
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#![feature(thread_local)]
|
#![feature(thread_local)]
|
||||||
#![feature(trace_macros)]
|
#![feature(trace_macros)]
|
||||||
#![feature(trusted_len)]
|
#![feature(trusted_len)]
|
||||||
|
#![feature(vec_remove_item)]
|
||||||
#![feature(stmt_expr_attributes)]
|
#![feature(stmt_expr_attributes)]
|
||||||
#![feature(integer_atomics)]
|
#![feature(integer_atomics)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
@ -71,8 +72,6 @@ extern crate rustc_data_structures;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate syntax;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
369
src/librustc/lint.rs
Normal file
369
src/librustc/lint.rs
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
|
use crate::ich::StableHashingContext;
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||||
|
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
|
||||||
|
use rustc_hir::HirId;
|
||||||
|
pub use rustc_session::lint::{builtin, Level, Lint, LintId, LintPass};
|
||||||
|
use rustc_session::{DiagnosticMessageId, Session};
|
||||||
|
use rustc_span::hygiene::MacroKind;
|
||||||
|
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
|
||||||
|
use rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
|
/// How a lint level was set.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
|
||||||
|
pub enum LintSource {
|
||||||
|
/// Lint is at the default level as declared
|
||||||
|
/// in rustc or a plugin.
|
||||||
|
Default,
|
||||||
|
|
||||||
|
/// Lint level was set by an attribute.
|
||||||
|
Node(Symbol, Span, Option<Symbol> /* RFC 2383 reason */),
|
||||||
|
|
||||||
|
/// Lint level was set by a command-line flag.
|
||||||
|
CommandLine(Symbol),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type LevelSource = (Level, LintSource);
|
||||||
|
|
||||||
|
pub struct LintLevelSets {
|
||||||
|
pub list: Vec<LintSet>,
|
||||||
|
pub lint_cap: Level,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum LintSet {
|
||||||
|
CommandLine {
|
||||||
|
// -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
|
||||||
|
// flag.
|
||||||
|
specs: FxHashMap<LintId, LevelSource>,
|
||||||
|
},
|
||||||
|
|
||||||
|
Node {
|
||||||
|
specs: FxHashMap<LintId, LevelSource>,
|
||||||
|
parent: u32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LintLevelSets {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_lint_level(
|
||||||
|
&self,
|
||||||
|
lint: &'static Lint,
|
||||||
|
idx: u32,
|
||||||
|
aux: Option<&FxHashMap<LintId, LevelSource>>,
|
||||||
|
sess: &Session,
|
||||||
|
) -> LevelSource {
|
||||||
|
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
|
||||||
|
|
||||||
|
// If `level` is none then we actually assume the default level for this
|
||||||
|
// lint.
|
||||||
|
let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));
|
||||||
|
|
||||||
|
// If we're about to issue a warning, check at the last minute for any
|
||||||
|
// directives against the warnings "lint". If, for example, there's an
|
||||||
|
// `allow(warnings)` in scope then we want to respect that instead.
|
||||||
|
if level == Level::Warn {
|
||||||
|
let (warnings_level, warnings_src) =
|
||||||
|
self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
|
||||||
|
if let Some(configured_warning_level) = warnings_level {
|
||||||
|
if configured_warning_level != Level::Warn {
|
||||||
|
level = configured_warning_level;
|
||||||
|
src = warnings_src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that we never exceed the `--cap-lints` argument.
|
||||||
|
level = cmp::min(level, self.lint_cap);
|
||||||
|
|
||||||
|
if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
|
||||||
|
// Ensure that we never exceed driver level.
|
||||||
|
level = cmp::min(*driver_level, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (level, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_lint_id_level(
|
||||||
|
&self,
|
||||||
|
id: LintId,
|
||||||
|
mut idx: u32,
|
||||||
|
aux: Option<&FxHashMap<LintId, LevelSource>>,
|
||||||
|
) -> (Option<Level>, LintSource) {
|
||||||
|
if let Some(specs) = aux {
|
||||||
|
if let Some(&(level, src)) = specs.get(&id) {
|
||||||
|
return (Some(level), src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
match self.list[idx as usize] {
|
||||||
|
LintSet::CommandLine { ref specs } => {
|
||||||
|
if let Some(&(level, src)) = specs.get(&id) {
|
||||||
|
return (Some(level), src);
|
||||||
|
}
|
||||||
|
return (None, LintSource::Default);
|
||||||
|
}
|
||||||
|
LintSet::Node { ref specs, parent } => {
|
||||||
|
if let Some(&(level, src)) = specs.get(&id) {
|
||||||
|
return (Some(level), src);
|
||||||
|
}
|
||||||
|
idx = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LintLevelMap {
|
||||||
|
pub sets: LintLevelSets,
|
||||||
|
pub id_to_set: FxHashMap<HirId, u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LintLevelMap {
|
||||||
|
/// If the `id` was previously registered with `register_id` when building
|
||||||
|
/// this `LintLevelMap` this returns the corresponding lint level and source
|
||||||
|
/// of the lint level for the lint provided.
|
||||||
|
///
|
||||||
|
/// If the `id` was not previously registered, returns `None`. If `None` is
|
||||||
|
/// returned then the parent of `id` should be acquired and this function
|
||||||
|
/// should be called again.
|
||||||
|
pub fn level_and_source(
|
||||||
|
&self,
|
||||||
|
lint: &'static Lint,
|
||||||
|
id: HirId,
|
||||||
|
session: &Session,
|
||||||
|
) -> Option<LevelSource> {
|
||||||
|
self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
|
||||||
|
#[inline]
|
||||||
|
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
||||||
|
let LintLevelMap { ref sets, ref id_to_set } = *self;
|
||||||
|
|
||||||
|
id_to_set.hash_stable(hcx, hasher);
|
||||||
|
|
||||||
|
let LintLevelSets { ref list, lint_cap } = *sets;
|
||||||
|
|
||||||
|
lint_cap.hash_stable(hcx, hasher);
|
||||||
|
|
||||||
|
hcx.while_hashing_spans(true, |hcx| {
|
||||||
|
list.len().hash_stable(hcx, hasher);
|
||||||
|
|
||||||
|
// We are working under the assumption here that the list of
|
||||||
|
// lint-sets is built in a deterministic order.
|
||||||
|
for lint_set in list {
|
||||||
|
::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);
|
||||||
|
|
||||||
|
match *lint_set {
|
||||||
|
LintSet::CommandLine { ref specs } => {
|
||||||
|
specs.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
LintSet::Node { ref specs, parent } => {
|
||||||
|
specs.hash_stable(hcx, hasher);
|
||||||
|
parent.hash_stable(hcx, hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn struct_lint_level<'a>(
|
||||||
|
sess: &'a Session,
|
||||||
|
lint: &'static Lint,
|
||||||
|
level: Level,
|
||||||
|
src: LintSource,
|
||||||
|
span: Option<MultiSpan>,
|
||||||
|
msg: &str,
|
||||||
|
) -> DiagnosticBuilder<'a> {
|
||||||
|
let mut err = match (level, span) {
|
||||||
|
(Level::Allow, _) => return sess.diagnostic().struct_dummy(),
|
||||||
|
(Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
|
||||||
|
(Level::Warn, None) => sess.struct_warn(msg),
|
||||||
|
(Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
|
||||||
|
(Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for future incompatibility lints and issue a stronger warning.
|
||||||
|
let lint_id = LintId::of(lint);
|
||||||
|
let future_incompatible = lint.future_incompatible;
|
||||||
|
|
||||||
|
// If this code originates in a foreign macro, aka something that this crate
|
||||||
|
// did not itself author, then it's likely that there's nothing this crate
|
||||||
|
// can do about it. We probably want to skip the lint entirely.
|
||||||
|
if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
|
||||||
|
// Any suggestions made here are likely to be incorrect, so anything we
|
||||||
|
// emit shouldn't be automatically fixed by rustfix.
|
||||||
|
err.allow_suggestions(false);
|
||||||
|
|
||||||
|
// If this is a future incompatible lint it'll become a hard error, so
|
||||||
|
// we have to emit *something*. Also allow lints to whitelist themselves
|
||||||
|
// on a case-by-case basis for emission in a foreign macro.
|
||||||
|
if future_incompatible.is_none() && !lint.report_in_external_macro {
|
||||||
|
err.cancel();
|
||||||
|
// Don't continue further, since we don't want to have
|
||||||
|
// `diag_span_note_once` called for a diagnostic that isn't emitted.
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = lint.name_lower();
|
||||||
|
match src {
|
||||||
|
LintSource::Default => {
|
||||||
|
sess.diag_note_once(
|
||||||
|
&mut err,
|
||||||
|
DiagnosticMessageId::from(lint),
|
||||||
|
&format!("`#[{}({})]` on by default", level.as_str(), name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
LintSource::CommandLine(lint_flag_val) => {
|
||||||
|
let flag = match level {
|
||||||
|
Level::Warn => "-W",
|
||||||
|
Level::Deny => "-D",
|
||||||
|
Level::Forbid => "-F",
|
||||||
|
Level::Allow => panic!(),
|
||||||
|
};
|
||||||
|
let hyphen_case_lint_name = name.replace("_", "-");
|
||||||
|
if lint_flag_val.as_str() == name {
|
||||||
|
sess.diag_note_once(
|
||||||
|
&mut err,
|
||||||
|
DiagnosticMessageId::from(lint),
|
||||||
|
&format!(
|
||||||
|
"requested on the command line with `{} {}`",
|
||||||
|
flag, hyphen_case_lint_name
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
|
||||||
|
sess.diag_note_once(
|
||||||
|
&mut err,
|
||||||
|
DiagnosticMessageId::from(lint),
|
||||||
|
&format!(
|
||||||
|
"`{} {}` implied by `{} {}`",
|
||||||
|
flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LintSource::Node(lint_attr_name, src, reason) => {
|
||||||
|
if let Some(rationale) = reason {
|
||||||
|
err.note(&rationale.as_str());
|
||||||
|
}
|
||||||
|
sess.diag_span_note_once(
|
||||||
|
&mut err,
|
||||||
|
DiagnosticMessageId::from(lint),
|
||||||
|
src,
|
||||||
|
"lint level defined here",
|
||||||
|
);
|
||||||
|
if lint_attr_name.as_str() != name {
|
||||||
|
let level_str = level.as_str();
|
||||||
|
sess.diag_note_once(
|
||||||
|
&mut err,
|
||||||
|
DiagnosticMessageId::from(lint),
|
||||||
|
&format!(
|
||||||
|
"`#[{}({})]` implied by `#[{}({})]`",
|
||||||
|
level_str, name, level_str, lint_attr_name
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err.code(DiagnosticId::Lint(name));
|
||||||
|
|
||||||
|
if let Some(future_incompatible) = future_incompatible {
|
||||||
|
const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
|
||||||
|
it will become a hard error";
|
||||||
|
|
||||||
|
let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
|
||||||
|
"once this method is added to the standard library, \
|
||||||
|
the ambiguity may cause an error or change in behavior!"
|
||||||
|
.to_owned()
|
||||||
|
} else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
|
||||||
|
"this borrowing pattern was not meant to be accepted, \
|
||||||
|
and may become a hard error in the future"
|
||||||
|
.to_owned()
|
||||||
|
} else if let Some(edition) = future_incompatible.edition {
|
||||||
|
format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
|
||||||
|
} else {
|
||||||
|
format!("{} in a future release!", STANDARD_MESSAGE)
|
||||||
|
};
|
||||||
|
let citation = format!("for more information, see {}", future_incompatible.reference);
|
||||||
|
err.warn(&explanation);
|
||||||
|
err.note(&citation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether `span` originates in a foreign crate's external macro.
|
||||||
|
///
|
||||||
|
/// This is used to test whether a lint should not even begin to figure out whether it should
|
||||||
|
/// be reported on the current node.
|
||||||
|
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
|
||||||
|
let expn_data = span.ctxt().outer_expn_data();
|
||||||
|
match expn_data.kind {
|
||||||
|
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
|
||||||
|
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
|
||||||
|
ExpnKind::Macro(MacroKind::Bang, _) => {
|
||||||
|
if expn_data.def_site.is_dummy() {
|
||||||
|
// Dummy span for the `def_site` means it's an external macro.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
match sess.source_map().span_to_snippet(expn_data.def_site) {
|
||||||
|
Ok(code) => !code.starts_with("macro_rules"),
|
||||||
|
// No snippet means external macro or compiler-builtin expansion.
|
||||||
|
Err(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExpnKind::Macro(..) => true, // definitely a plugin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_elided_lifetime_in_path_suggestion(
|
||||||
|
sess: &Session,
|
||||||
|
db: &mut DiagnosticBuilder<'_>,
|
||||||
|
n: usize,
|
||||||
|
path_span: Span,
|
||||||
|
incl_angl_brckt: bool,
|
||||||
|
insertion_span: Span,
|
||||||
|
anon_lts: String,
|
||||||
|
) {
|
||||||
|
let (replace_span, suggestion) = if incl_angl_brckt {
|
||||||
|
(insertion_span, anon_lts)
|
||||||
|
} else {
|
||||||
|
// When possible, prefer a suggestion that replaces the whole
|
||||||
|
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
||||||
|
// at a point (which makes for an ugly/confusing label)
|
||||||
|
if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
|
||||||
|
// But our spans can get out of whack due to macros; if the place we think
|
||||||
|
// we want to insert `'_` isn't even within the path expression's span, we
|
||||||
|
// should bail out of making any suggestion rather than panicking on a
|
||||||
|
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
||||||
|
// FIXME: can we do better?
|
||||||
|
if insertion_span.lo().0 < path_span.lo().0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
||||||
|
if insertion_index > snippet.len() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let (before, after) = snippet.split_at(insertion_index);
|
||||||
|
(path_span, format!("{}{}{}", before, anon_lts, after))
|
||||||
|
} else {
|
||||||
|
(insertion_span, anon_lts)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
db.span_suggestion(
|
||||||
|
replace_span,
|
||||||
|
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
|
||||||
|
suggestion,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,550 +0,0 @@
|
||||||
use std::cmp;
|
|
||||||
|
|
||||||
use crate::ich::StableHashingContext;
|
|
||||||
use crate::lint::builtin;
|
|
||||||
use crate::lint::context::{CheckLintNameResult, LintStore};
|
|
||||||
use crate::lint::{self, Level, Lint, LintId, LintSource};
|
|
||||||
use crate::session::Session;
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
|
||||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
|
||||||
use rustc_hir::HirId;
|
|
||||||
use rustc_span::source_map::MultiSpan;
|
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
|
||||||
use syntax::ast;
|
|
||||||
use syntax::attr;
|
|
||||||
use syntax::print::pprust;
|
|
||||||
use syntax::sess::feature_err;
|
|
||||||
|
|
||||||
use rustc_error_codes::*;
|
|
||||||
|
|
||||||
pub struct LintLevelSets {
|
|
||||||
list: Vec<LintSet>,
|
|
||||||
lint_cap: Level,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LintSet {
|
|
||||||
CommandLine {
|
|
||||||
// -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
|
|
||||||
// flag.
|
|
||||||
specs: FxHashMap<LintId, (Level, LintSource)>,
|
|
||||||
},
|
|
||||||
|
|
||||||
Node {
|
|
||||||
specs: FxHashMap<LintId, (Level, LintSource)>,
|
|
||||||
parent: u32,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LintLevelSets {
|
|
||||||
pub fn new(sess: &Session, lint_store: &LintStore) -> LintLevelSets {
|
|
||||||
let mut me = LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid };
|
|
||||||
me.process_command_line(sess, lint_store);
|
|
||||||
return me;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn builder<'a>(
|
|
||||||
sess: &'a Session,
|
|
||||||
warn_about_weird_lints: bool,
|
|
||||||
store: &LintStore,
|
|
||||||
) -> LintLevelsBuilder<'a> {
|
|
||||||
LintLevelsBuilder::new(sess, warn_about_weird_lints, LintLevelSets::new(sess, store))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
|
|
||||||
let mut specs = FxHashMap::default();
|
|
||||||
self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
|
|
||||||
|
|
||||||
for &(ref lint_name, level) in &sess.opts.lint_opts {
|
|
||||||
store.check_lint_name_cmdline(sess, &lint_name, level);
|
|
||||||
|
|
||||||
// If the cap is less than this specified level, e.g., if we've got
|
|
||||||
// `--cap-lints allow` but we've also got `-D foo` then we ignore
|
|
||||||
// this specification as the lint cap will set it to allow anyway.
|
|
||||||
let level = cmp::min(level, self.lint_cap);
|
|
||||||
|
|
||||||
let lint_flag_val = Symbol::intern(lint_name);
|
|
||||||
let ids = match store.find_lints(&lint_name) {
|
|
||||||
Ok(ids) => ids,
|
|
||||||
Err(_) => continue, // errors handled in check_lint_name_cmdline above
|
|
||||||
};
|
|
||||||
for id in ids {
|
|
||||||
let src = LintSource::CommandLine(lint_flag_val);
|
|
||||||
specs.insert(id, (level, src));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.list.push(LintSet::CommandLine { specs: specs });
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_lint_level(
|
|
||||||
&self,
|
|
||||||
lint: &'static Lint,
|
|
||||||
idx: u32,
|
|
||||||
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
|
|
||||||
sess: &Session,
|
|
||||||
) -> (Level, LintSource) {
|
|
||||||
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
|
|
||||||
|
|
||||||
// If `level` is none then we actually assume the default level for this
|
|
||||||
// lint.
|
|
||||||
let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition()));
|
|
||||||
|
|
||||||
// If we're about to issue a warning, check at the last minute for any
|
|
||||||
// directives against the warnings "lint". If, for example, there's an
|
|
||||||
// `allow(warnings)` in scope then we want to respect that instead.
|
|
||||||
if level == Level::Warn {
|
|
||||||
let (warnings_level, warnings_src) =
|
|
||||||
self.get_lint_id_level(LintId::of(lint::builtin::WARNINGS), idx, aux);
|
|
||||||
if let Some(configured_warning_level) = warnings_level {
|
|
||||||
if configured_warning_level != Level::Warn {
|
|
||||||
level = configured_warning_level;
|
|
||||||
src = warnings_src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that we never exceed the `--cap-lints` argument.
|
|
||||||
level = cmp::min(level, self.lint_cap);
|
|
||||||
|
|
||||||
if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
|
|
||||||
// Ensure that we never exceed driver level.
|
|
||||||
level = cmp::min(*driver_level, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (level, src);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_lint_id_level(
|
|
||||||
&self,
|
|
||||||
id: LintId,
|
|
||||||
mut idx: u32,
|
|
||||||
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
|
|
||||||
) -> (Option<Level>, LintSource) {
|
|
||||||
if let Some(specs) = aux {
|
|
||||||
if let Some(&(level, src)) = specs.get(&id) {
|
|
||||||
return (Some(level), src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loop {
|
|
||||||
match self.list[idx as usize] {
|
|
||||||
LintSet::CommandLine { ref specs } => {
|
|
||||||
if let Some(&(level, src)) = specs.get(&id) {
|
|
||||||
return (Some(level), src);
|
|
||||||
}
|
|
||||||
return (None, LintSource::Default);
|
|
||||||
}
|
|
||||||
LintSet::Node { ref specs, parent } => {
|
|
||||||
if let Some(&(level, src)) = specs.get(&id) {
|
|
||||||
return (Some(level), src);
|
|
||||||
}
|
|
||||||
idx = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LintLevelsBuilder<'a> {
|
|
||||||
sess: &'a Session,
|
|
||||||
sets: LintLevelSets,
|
|
||||||
id_to_set: FxHashMap<HirId, u32>,
|
|
||||||
cur: u32,
|
|
||||||
warn_about_weird_lints: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct BuilderPush {
|
|
||||||
prev: u32,
|
|
||||||
pub changed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LintLevelsBuilder<'a> {
|
|
||||||
pub fn new(
|
|
||||||
sess: &'a Session,
|
|
||||||
warn_about_weird_lints: bool,
|
|
||||||
sets: LintLevelSets,
|
|
||||||
) -> LintLevelsBuilder<'a> {
|
|
||||||
assert_eq!(sets.list.len(), 1);
|
|
||||||
LintLevelsBuilder {
|
|
||||||
sess,
|
|
||||||
sets,
|
|
||||||
cur: 0,
|
|
||||||
id_to_set: Default::default(),
|
|
||||||
warn_about_weird_lints,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pushes a list of AST lint attributes onto this context.
|
|
||||||
///
|
|
||||||
/// This function will return a `BuilderPush` object which should be passed
|
|
||||||
/// to `pop` when this scope for the attributes provided is exited.
|
|
||||||
///
|
|
||||||
/// This function will perform a number of tasks:
|
|
||||||
///
|
|
||||||
/// * It'll validate all lint-related attributes in `attrs`
|
|
||||||
/// * It'll mark all lint-related attributes as used
|
|
||||||
/// * Lint levels will be updated based on the attributes provided
|
|
||||||
/// * Lint attributes are validated, e.g., a #[forbid] can't be switched to
|
|
||||||
/// #[allow]
|
|
||||||
///
|
|
||||||
/// Don't forget to call `pop`!
|
|
||||||
pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
|
|
||||||
let mut specs = FxHashMap::default();
|
|
||||||
let sess = self.sess;
|
|
||||||
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
|
|
||||||
for attr in attrs {
|
|
||||||
let level = match Level::from_symbol(attr.name_or_empty()) {
|
|
||||||
None => continue,
|
|
||||||
Some(lvl) => lvl,
|
|
||||||
};
|
|
||||||
|
|
||||||
let meta = unwrap_or!(attr.meta(), continue);
|
|
||||||
attr::mark_used(attr);
|
|
||||||
|
|
||||||
let mut metas = unwrap_or!(meta.meta_item_list(), continue);
|
|
||||||
|
|
||||||
if metas.is_empty() {
|
|
||||||
// FIXME (#55112): issue unused-attributes lint for `#[level()]`
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before processing the lint names, look for a reason (RFC 2383)
|
|
||||||
// at the end.
|
|
||||||
let mut reason = None;
|
|
||||||
let tail_li = &metas[metas.len() - 1];
|
|
||||||
if let Some(item) = tail_li.meta_item() {
|
|
||||||
match item.kind {
|
|
||||||
ast::MetaItemKind::Word => {} // actual lint names handled later
|
|
||||||
ast::MetaItemKind::NameValue(ref name_value) => {
|
|
||||||
if item.path == sym::reason {
|
|
||||||
// found reason, reslice meta list to exclude it
|
|
||||||
metas = &metas[0..metas.len() - 1];
|
|
||||||
// FIXME (#55112): issue unused-attributes lint if we thereby
|
|
||||||
// don't have any lint names (`#[level(reason = "foo")]`)
|
|
||||||
if let ast::LitKind::Str(rationale, _) = name_value.kind {
|
|
||||||
if !self.sess.features_untracked().lint_reasons {
|
|
||||||
feature_err(
|
|
||||||
&self.sess.parse_sess,
|
|
||||||
sym::lint_reasons,
|
|
||||||
item.span,
|
|
||||||
"lint reasons are experimental",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
reason = Some(rationale);
|
|
||||||
} else {
|
|
||||||
bad_attr(name_value.span)
|
|
||||||
.span_label(name_value.span, "reason must be a string literal")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bad_attr(item.span)
|
|
||||||
.span_label(item.span, "bad attribute argument")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::MetaItemKind::List(_) => {
|
|
||||||
bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for li in metas {
|
|
||||||
let meta_item = match li.meta_item() {
|
|
||||||
Some(meta_item) if meta_item.is_word() => meta_item,
|
|
||||||
_ => {
|
|
||||||
let sp = li.span();
|
|
||||||
let mut err = bad_attr(sp);
|
|
||||||
let mut add_label = true;
|
|
||||||
if let Some(item) = li.meta_item() {
|
|
||||||
if let ast::MetaItemKind::NameValue(_) = item.kind {
|
|
||||||
if item.path == sym::reason {
|
|
||||||
err.span_label(sp, "reason in lint attribute must come last");
|
|
||||||
add_label = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if add_label {
|
|
||||||
err.span_label(sp, "bad attribute argument");
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let tool_name = if meta_item.path.segments.len() > 1 {
|
|
||||||
let tool_ident = meta_item.path.segments[0].ident;
|
|
||||||
if !attr::is_known_lint_tool(tool_ident) {
|
|
||||||
struct_span_err!(
|
|
||||||
sess,
|
|
||||||
tool_ident.span,
|
|
||||||
E0710,
|
|
||||||
"an unknown tool name found in scoped lint: `{}`",
|
|
||||||
pprust::path_to_string(&meta_item.path),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(tool_ident.name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
|
|
||||||
match store.check_lint_name(&name.as_str(), tool_name) {
|
|
||||||
CheckLintNameResult::Ok(ids) => {
|
|
||||||
let src = LintSource::Node(name, li.span(), reason);
|
|
||||||
for id in ids {
|
|
||||||
specs.insert(*id, (level, src));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckLintNameResult::Tool(result) => {
|
|
||||||
match result {
|
|
||||||
Ok(ids) => {
|
|
||||||
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
|
|
||||||
let src = LintSource::Node(
|
|
||||||
Symbol::intern(complete_name),
|
|
||||||
li.span(),
|
|
||||||
reason,
|
|
||||||
);
|
|
||||||
for id in ids {
|
|
||||||
specs.insert(*id, (level, src));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err((Some(ids), new_lint_name)) => {
|
|
||||||
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
|
||||||
let (lvl, src) =
|
|
||||||
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
|
|
||||||
let msg = format!(
|
|
||||||
"lint name `{}` is deprecated \
|
|
||||||
and may not have an effect in the future. \
|
|
||||||
Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
|
|
||||||
name
|
|
||||||
);
|
|
||||||
lint::struct_lint_level(
|
|
||||||
self.sess,
|
|
||||||
lint,
|
|
||||||
lvl,
|
|
||||||
src,
|
|
||||||
Some(li.span().into()),
|
|
||||||
&msg,
|
|
||||||
)
|
|
||||||
.span_suggestion(
|
|
||||||
li.span(),
|
|
||||||
"change it to",
|
|
||||||
new_lint_name.to_string(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
|
|
||||||
let src = LintSource::Node(
|
|
||||||
Symbol::intern(&new_lint_name),
|
|
||||||
li.span(),
|
|
||||||
reason,
|
|
||||||
);
|
|
||||||
for id in ids {
|
|
||||||
specs.insert(*id, (level, src));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err((None, _)) => {
|
|
||||||
// If Tool(Err(None, _)) is returned, then either the lint does not
|
|
||||||
// exist in the tool or the code was not compiled with the tool and
|
|
||||||
// therefore the lint was never added to the `LintStore`. To detect
|
|
||||||
// this is the responsibility of the lint tool.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ if !self.warn_about_weird_lints => {}
|
|
||||||
|
|
||||||
CheckLintNameResult::Warning(msg, renamed) => {
|
|
||||||
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
|
||||||
let (level, src) =
|
|
||||||
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
|
|
||||||
let mut err = lint::struct_lint_level(
|
|
||||||
self.sess,
|
|
||||||
lint,
|
|
||||||
level,
|
|
||||||
src,
|
|
||||||
Some(li.span().into()),
|
|
||||||
&msg,
|
|
||||||
);
|
|
||||||
if let Some(new_name) = renamed {
|
|
||||||
err.span_suggestion(
|
|
||||||
li.span(),
|
|
||||||
"use the new name",
|
|
||||||
new_name,
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
CheckLintNameResult::NoLint(suggestion) => {
|
|
||||||
let lint = builtin::UNKNOWN_LINTS;
|
|
||||||
let (level, src) =
|
|
||||||
self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
|
|
||||||
let msg = format!("unknown lint: `{}`", name);
|
|
||||||
let mut db = lint::struct_lint_level(
|
|
||||||
self.sess,
|
|
||||||
lint,
|
|
||||||
level,
|
|
||||||
src,
|
|
||||||
Some(li.span().into()),
|
|
||||||
&msg,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(suggestion) = suggestion {
|
|
||||||
db.span_suggestion(
|
|
||||||
li.span(),
|
|
||||||
"did you mean",
|
|
||||||
suggestion.to_string(),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
db.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (id, &(level, ref src)) in specs.iter() {
|
|
||||||
if level == Level::Forbid {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) {
|
|
||||||
(Some(Level::Forbid), src) => src,
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
let forbidden_lint_name = match forbid_src {
|
|
||||||
LintSource::Default => id.to_string(),
|
|
||||||
LintSource::Node(name, _, _) => name.to_string(),
|
|
||||||
LintSource::CommandLine(name) => name.to_string(),
|
|
||||||
};
|
|
||||||
let (lint_attr_name, lint_attr_span) = match *src {
|
|
||||||
LintSource::Node(name, span, _) => (name, span),
|
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
let mut diag_builder = struct_span_err!(
|
|
||||||
self.sess,
|
|
||||||
lint_attr_span,
|
|
||||||
E0453,
|
|
||||||
"{}({}) overruled by outer forbid({})",
|
|
||||||
level.as_str(),
|
|
||||||
lint_attr_name,
|
|
||||||
forbidden_lint_name
|
|
||||||
);
|
|
||||||
diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
|
|
||||||
match forbid_src {
|
|
||||||
LintSource::Default => {}
|
|
||||||
LintSource::Node(_, forbid_source_span, reason) => {
|
|
||||||
diag_builder.span_label(forbid_source_span, "`forbid` level set here");
|
|
||||||
if let Some(rationale) = reason {
|
|
||||||
diag_builder.note(&rationale.as_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LintSource::CommandLine(_) => {
|
|
||||||
diag_builder.note("`forbid` lint level was set on command line");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diag_builder.emit();
|
|
||||||
// don't set a separate error for every lint in the group
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let prev = self.cur;
|
|
||||||
if specs.len() > 0 {
|
|
||||||
self.cur = self.sets.list.len() as u32;
|
|
||||||
self.sets.list.push(LintSet::Node { specs: specs, parent: prev });
|
|
||||||
}
|
|
||||||
|
|
||||||
BuilderPush { prev: prev, changed: prev != self.cur }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called after `push` when the scope of a set of attributes are exited.
|
|
||||||
pub fn pop(&mut self, push: BuilderPush) {
|
|
||||||
self.cur = push.prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used to emit a lint-related diagnostic based on the current state of
|
|
||||||
/// this lint context.
|
|
||||||
pub fn struct_lint(
|
|
||||||
&self,
|
|
||||||
lint: &'static Lint,
|
|
||||||
span: Option<MultiSpan>,
|
|
||||||
msg: &str,
|
|
||||||
) -> DiagnosticBuilder<'a> {
|
|
||||||
let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
|
|
||||||
lint::struct_lint_level(self.sess, lint, level, src, span, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Registers the ID provided with the current set of lints stored in
|
|
||||||
/// this context.
|
|
||||||
pub fn register_id(&mut self, id: HirId) {
|
|
||||||
self.id_to_set.insert(id, self.cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build(self) -> LintLevelSets {
|
|
||||||
self.sets
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_map(self) -> LintLevelMap {
|
|
||||||
LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LintLevelMap {
|
|
||||||
sets: LintLevelSets,
|
|
||||||
id_to_set: FxHashMap<HirId, u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LintLevelMap {
|
|
||||||
/// If the `id` was previously registered with `register_id` when building
|
|
||||||
/// this `LintLevelMap` this returns the corresponding lint level and source
|
|
||||||
/// of the lint level for the lint provided.
|
|
||||||
///
|
|
||||||
/// If the `id` was not previously registered, returns `None`. If `None` is
|
|
||||||
/// returned then the parent of `id` should be acquired and this function
|
|
||||||
/// should be called again.
|
|
||||||
pub fn level_and_source(
|
|
||||||
&self,
|
|
||||||
lint: &'static Lint,
|
|
||||||
id: HirId,
|
|
||||||
session: &Session,
|
|
||||||
) -> Option<(Level, LintSource)> {
|
|
||||||
self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
|
|
||||||
#[inline]
|
|
||||||
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
|
||||||
let LintLevelMap { ref sets, ref id_to_set } = *self;
|
|
||||||
|
|
||||||
id_to_set.hash_stable(hcx, hasher);
|
|
||||||
|
|
||||||
let LintLevelSets { ref list, lint_cap } = *sets;
|
|
||||||
|
|
||||||
lint_cap.hash_stable(hcx, hasher);
|
|
||||||
|
|
||||||
hcx.while_hashing_spans(true, |hcx| {
|
|
||||||
list.len().hash_stable(hcx, hasher);
|
|
||||||
|
|
||||||
// We are working under the assumption here that the list of
|
|
||||||
// lint-sets is built in a deterministic order.
|
|
||||||
for lint_set in list {
|
|
||||||
::std::mem::discriminant(lint_set).hash_stable(hcx, hasher);
|
|
||||||
|
|
||||||
match *lint_set {
|
|
||||||
LintSet::CommandLine { ref specs } => {
|
|
||||||
specs.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
LintSet::Node { ref specs, parent } => {
|
|
||||||
specs.hash_stable(hcx, hasher);
|
|
||||||
parent.hash_stable(hcx, hasher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
pub use self::StabilityLevel::*;
|
pub use self::StabilityLevel::*;
|
||||||
|
|
||||||
use crate::lint::{self, in_derive_expansion, Lint};
|
|
||||||
use crate::session::{DiagnosticMessageId, Session};
|
use crate::session::{DiagnosticMessageId, Session};
|
||||||
use crate::ty::{self, TyCtxt};
|
use crate::ty::{self, TyCtxt};
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
@ -13,7 +12,7 @@ use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
|
||||||
use rustc_hir::{self, HirId};
|
use rustc_hir::{self, HirId};
|
||||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
use rustc_session::lint::{self, BuiltinLintDiagnostics, Lint, LintBuffer};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
use rustc_span::{MultiSpan, Span};
|
use rustc_span::{MultiSpan, Span};
|
||||||
use syntax::ast::CRATE_NODE_ID;
|
use syntax::ast::CRATE_NODE_ID;
|
||||||
|
@ -201,7 +200,7 @@ pub fn early_report_deprecation(
|
||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
if in_derive_expansion(span) {
|
if span.in_derive_expansion() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +217,7 @@ fn late_report_deprecation(
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
) {
|
) {
|
||||||
if in_derive_expansion(span) {
|
if span.in_derive_expansion() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or(lint_root);
|
.unwrap_or(lint_root);
|
||||||
tcx.struct_span_lint_hir(
|
tcx.struct_span_lint_hir(
|
||||||
crate::rustc::lint::builtin::CONST_ERR,
|
rustc_session::lint::builtin::CONST_ERR,
|
||||||
hir_id,
|
hir_id,
|
||||||
tcx.span,
|
tcx.span,
|
||||||
message,
|
message,
|
||||||
|
|
|
@ -82,7 +82,7 @@ rustc_queries! {
|
||||||
desc { "looking up the native libraries of a linked crate" }
|
desc { "looking up the native libraries of a linked crate" }
|
||||||
}
|
}
|
||||||
|
|
||||||
query lint_levels(_: CrateNum) -> &'tcx lint::LintLevelMap {
|
query lint_levels(_: CrateNum) -> &'tcx LintLevelMap {
|
||||||
eval_always
|
eval_always
|
||||||
desc { "computing the lint levels for items in this crate" }
|
desc { "computing the lint levels for items in this crate" }
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,18 @@
|
||||||
|
|
||||||
use super::elaborate_predicates;
|
use super::elaborate_predicates;
|
||||||
|
|
||||||
use crate::lint;
|
|
||||||
use crate::traits::{self, Obligation, ObligationCause};
|
use crate::traits::{self, Obligation, ObligationCause};
|
||||||
use crate::ty::subst::{InternalSubsts, Subst};
|
use crate::ty::subst::{InternalSubsts, Subst};
|
||||||
use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
use syntax::ast;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::iter::{self};
|
use std::iter::{self};
|
||||||
use syntax::ast::{self};
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ObjectSafetyViolation {
|
pub enum ObjectSafetyViolation {
|
||||||
|
@ -178,16 +179,17 @@ fn object_safety_violations_for_trait(
|
||||||
{
|
{
|
||||||
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
|
// Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
|
||||||
// It's also hard to get a use site span, so we use the method definition span.
|
// It's also hard to get a use site span, so we use the method definition span.
|
||||||
tcx.lint_node_note(
|
tcx.struct_span_lint_hir(
|
||||||
lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
|
WHERE_CLAUSES_OBJECT_SAFETY,
|
||||||
hir::CRATE_HIR_ID,
|
hir::CRATE_HIR_ID,
|
||||||
*span,
|
*span,
|
||||||
&format!(
|
&format!(
|
||||||
"the trait `{}` cannot be made into an object",
|
"the trait `{}` cannot be made into an object",
|
||||||
tcx.def_path_str(trait_def_id)
|
tcx.def_path_str(trait_def_id)
|
||||||
),
|
),
|
||||||
&violation.error_msg(),
|
)
|
||||||
);
|
.note(&violation.error_msg())
|
||||||
|
.emit();
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
|
|
|
@ -1467,7 +1467,7 @@ fn assoc_ty_def(
|
||||||
// cycle error if the specialization graph is currently being built.
|
// cycle error if the specialization graph is currently being built.
|
||||||
let impl_node = specialization_graph::Node::Impl(impl_def_id);
|
let impl_node = specialization_graph::Node::Impl(impl_def_id);
|
||||||
for item in impl_node.items(tcx) {
|
for item in impl_node.items(tcx) {
|
||||||
if item.kind == ty::AssocKind::Type
|
if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy)
|
||||||
&& tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
|
&& tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
|
||||||
{
|
{
|
||||||
return specialization_graph::NodeItem {
|
return specialization_graph::NodeItem {
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
pub mod specialization_graph;
|
pub mod specialization_graph;
|
||||||
|
|
||||||
use crate::infer::{InferCtxt, InferOk};
|
use crate::infer::{InferCtxt, InferOk};
|
||||||
use crate::lint;
|
|
||||||
use crate::traits::select::IntercrateAmbiguityCause;
|
use crate::traits::select::IntercrateAmbiguityCause;
|
||||||
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
|
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
|
||||||
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
|
||||||
|
@ -20,6 +19,7 @@ use crate::ty::{self, TyCtxt, TypeFoldable};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::struct_span_err;
|
use rustc_errors::struct_span_err;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
|
||||||
use rustc_span::DUMMY_SP;
|
use rustc_span::DUMMY_SP;
|
||||||
|
|
||||||
use super::util::impl_trait_ref_and_oblig;
|
use super::util::impl_trait_ref_and_oblig;
|
||||||
|
@ -342,7 +342,7 @@ pub(super) fn specialization_graph_provider(
|
||||||
unreachable!("converted to hard error above")
|
unreachable!("converted to hard error above")
|
||||||
}
|
}
|
||||||
FutureCompatOverlapErrorKind::Issue33140 => {
|
FutureCompatOverlapErrorKind::Issue33140 => {
|
||||||
lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS
|
ORDER_DEPENDENT_TRAIT_OBJECTS
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
tcx.struct_span_lint_hir(
|
tcx.struct_span_lint_hir(
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::hir::map as hir_map;
|
||||||
use crate::hir::map::DefPathHash;
|
use crate::hir::map::DefPathHash;
|
||||||
use crate::ich::{NodeIdHashingMode, StableHashingContext};
|
use crate::ich::{NodeIdHashingMode, StableHashingContext};
|
||||||
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
|
||||||
use crate::lint::{self, Lint};
|
use crate::lint::{struct_lint_level, LintSource};
|
||||||
use crate::middle;
|
use crate::middle;
|
||||||
use crate::middle::cstore::CrateStoreDyn;
|
use crate::middle::cstore::CrateStoreDyn;
|
||||||
use crate::middle::cstore::EncodedMetadata;
|
use crate::middle::cstore::EncodedMetadata;
|
||||||
|
@ -20,9 +20,6 @@ use crate::mir::interpret::{Allocation, ConstValue, Scalar};
|
||||||
use crate::mir::{
|
use crate::mir::{
|
||||||
interpret, BodyAndCache, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
|
interpret, BodyAndCache, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
|
||||||
};
|
};
|
||||||
use crate::session::config::CrateType;
|
|
||||||
use crate::session::config::{BorrowckMode, OutputFilenames};
|
|
||||||
use crate::session::Session;
|
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
|
use crate::traits::{Clause, Clauses, Goal, GoalKind, Goals};
|
||||||
use crate::ty::free_region_map::FreeRegionMap;
|
use crate::ty::free_region_map::FreeRegionMap;
|
||||||
|
@ -44,11 +41,15 @@ use crate::ty::{ExistentialPredicate, InferTy, ParamTy, PolyFnSig, Predicate, Pr
|
||||||
use crate::ty::{InferConst, ParamConst};
|
use crate::ty::{InferConst, ParamConst};
|
||||||
use crate::ty::{List, TyKind, TyS};
|
use crate::ty::{List, TyKind, TyS};
|
||||||
use crate::util::common::ErrorReported;
|
use crate::util::common::ErrorReported;
|
||||||
|
use rustc_data_structures::sync;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, DefIndex, LOCAL_CRATE};
|
||||||
use rustc_hir::{HirId, Node, TraitCandidate};
|
use rustc_hir::{HirId, Node, TraitCandidate};
|
||||||
use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet};
|
use rustc_hir::{ItemKind, ItemLocalId, ItemLocalMap, ItemLocalSet};
|
||||||
|
use rustc_session::config::CrateType;
|
||||||
|
use rustc_session::config::{BorrowckMode, OutputFilenames};
|
||||||
|
use rustc_session::Session;
|
||||||
|
|
||||||
use arena::SyncDroplessArena;
|
use arena::SyncDroplessArena;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
@ -61,6 +62,7 @@ use rustc_data_structures::sync::{Lock, Lrc, WorkerLocal};
|
||||||
use rustc_errors::DiagnosticBuilder;
|
use rustc_errors::DiagnosticBuilder;
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
use rustc_session::lint::{Level, Lint};
|
||||||
use rustc_session::node_id::NodeMap;
|
use rustc_session::node_id::NodeMap;
|
||||||
use rustc_span::source_map::MultiSpan;
|
use rustc_span::source_map::MultiSpan;
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
|
@ -946,7 +948,11 @@ pub struct GlobalCtxt<'tcx> {
|
||||||
|
|
||||||
pub sess: &'tcx Session,
|
pub sess: &'tcx Session,
|
||||||
|
|
||||||
pub lint_store: Lrc<lint::LintStore>,
|
/// This only ever stores a `LintStore` but we don't want a dependency on that type here.
|
||||||
|
///
|
||||||
|
/// FIXME(Centril): consider `dyn LintStoreMarker` once
|
||||||
|
/// we can upcast to `Any` for some additional type safety.
|
||||||
|
pub lint_store: Lrc<dyn Any + sync::Sync + sync::Send>,
|
||||||
|
|
||||||
pub dep_graph: DepGraph,
|
pub dep_graph: DepGraph,
|
||||||
|
|
||||||
|
@ -1115,7 +1121,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
/// reference to the context, to allow formatting values that need it.
|
/// reference to the context, to allow formatting values that need it.
|
||||||
pub fn create_global_ctxt(
|
pub fn create_global_ctxt(
|
||||||
s: &'tcx Session,
|
s: &'tcx Session,
|
||||||
lint_store: Lrc<lint::LintStore>,
|
lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
|
||||||
local_providers: ty::query::Providers<'tcx>,
|
local_providers: ty::query::Providers<'tcx>,
|
||||||
extern_providers: ty::query::Providers<'tcx>,
|
extern_providers: ty::query::Providers<'tcx>,
|
||||||
arenas: &'tcx AllArenas,
|
arenas: &'tcx AllArenas,
|
||||||
|
@ -2551,57 +2557,29 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
iter.intern_with(|xs| self.intern_goals(xs))
|
iter.intern_with(|xs| self.intern_goals(xs))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lint_hir<S: Into<MultiSpan>>(
|
pub fn lint_hir(
|
||||||
self,
|
self,
|
||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
span: S,
|
span: impl Into<MultiSpan>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) {
|
) {
|
||||||
self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
|
self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lint_hir_note<S: Into<MultiSpan>>(
|
|
||||||
self,
|
|
||||||
lint: &'static Lint,
|
|
||||||
hir_id: HirId,
|
|
||||||
span: S,
|
|
||||||
msg: &str,
|
|
||||||
note: &str,
|
|
||||||
) {
|
|
||||||
let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg);
|
|
||||||
err.note(note);
|
|
||||||
err.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lint_node_note<S: Into<MultiSpan>>(
|
|
||||||
self,
|
|
||||||
lint: &'static Lint,
|
|
||||||
id: hir::HirId,
|
|
||||||
span: S,
|
|
||||||
msg: &str,
|
|
||||||
note: &str,
|
|
||||||
) {
|
|
||||||
let mut err = self.struct_span_lint_hir(lint, id, span.into(), msg);
|
|
||||||
err.note(note);
|
|
||||||
err.emit()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Walks upwards from `id` to find a node which might change lint levels with attributes.
|
/// Walks upwards from `id` to find a node which might change lint levels with attributes.
|
||||||
/// It stops at `bound` and just returns it if reached.
|
/// It stops at `bound` and just returns it if reached.
|
||||||
pub fn maybe_lint_level_root_bounded(
|
pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId {
|
||||||
self,
|
let hir = self.hir();
|
||||||
mut id: hir::HirId,
|
|
||||||
bound: hir::HirId,
|
|
||||||
) -> hir::HirId {
|
|
||||||
loop {
|
loop {
|
||||||
if id == bound {
|
if id == bound {
|
||||||
return bound;
|
return bound;
|
||||||
}
|
}
|
||||||
if lint::maybe_lint_level_root(self, id) {
|
|
||||||
|
if hir.attrs(id).iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
let next = self.hir().get_parent_node(id);
|
let next = hir.get_parent_node(id);
|
||||||
if next == id {
|
if next == id {
|
||||||
bug!("lint traversal reached the root of the crate");
|
bug!("lint traversal reached the root of the crate");
|
||||||
}
|
}
|
||||||
|
@ -2613,7 +2591,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
self,
|
self,
|
||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
mut id: hir::HirId,
|
mut id: hir::HirId,
|
||||||
) -> (lint::Level, lint::LintSource) {
|
) -> (Level, LintSource) {
|
||||||
let sets = self.lint_levels(LOCAL_CRATE);
|
let sets = self.lint_levels(LOCAL_CRATE);
|
||||||
loop {
|
loop {
|
||||||
if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
|
if let Some(pair) = sets.level_and_source(lint, id, self.sess) {
|
||||||
|
@ -2627,15 +2605,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn struct_span_lint_hir<S: Into<MultiSpan>>(
|
pub fn struct_span_lint_hir(
|
||||||
self,
|
self,
|
||||||
lint: &'static Lint,
|
lint: &'static Lint,
|
||||||
hir_id: HirId,
|
hir_id: HirId,
|
||||||
span: S,
|
span: impl Into<MultiSpan>,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> DiagnosticBuilder<'tcx> {
|
) -> DiagnosticBuilder<'tcx> {
|
||||||
let (level, src) = self.lint_level_at_node(lint, hir_id);
|
let (level, src) = self.lint_level_at_node(lint, hir_id);
|
||||||
lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
|
struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn struct_lint_node(
|
pub fn struct_lint_node(
|
||||||
|
@ -2645,7 +2623,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
msg: &str,
|
msg: &str,
|
||||||
) -> DiagnosticBuilder<'tcx> {
|
) -> DiagnosticBuilder<'tcx> {
|
||||||
let (level, src) = self.lint_level_at_node(lint, id);
|
let (level, src) = self.lint_level_at_node(lint, id);
|
||||||
lint::struct_lint_level(self.sess, lint, level, src, None, msg)
|
struct_lint_level(self.sess, lint, level, src, None, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
|
pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::dep_graph::{self, DepNode};
|
use crate::dep_graph::{self, DepNode};
|
||||||
use crate::hir::exports::Export;
|
use crate::hir::exports::Export;
|
||||||
use crate::infer::canonical::{self, Canonical};
|
use crate::infer::canonical::{self, Canonical};
|
||||||
use crate::lint;
|
use crate::lint::LintLevelMap;
|
||||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||||
use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind};
|
use crate::middle::cstore::{CrateSource, DepKind, NativeLibraryKind};
|
||||||
use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary};
|
use crate::middle::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLibrary};
|
||||||
|
|
|
@ -37,7 +37,6 @@ use rustc::arena::Arena;
|
||||||
use rustc::dep_graph::DepGraph;
|
use rustc::dep_graph::DepGraph;
|
||||||
use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions};
|
use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions};
|
||||||
use rustc::hir::map::Map;
|
use rustc::hir::map::Map;
|
||||||
use rustc::lint::builtin;
|
|
||||||
use rustc::{bug, span_bug};
|
use rustc::{bug, span_bug};
|
||||||
use rustc_data_structures::captures::Captures;
|
use rustc_data_structures::captures::Captures;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
@ -51,7 +50,7 @@ use rustc_hir::intravisit;
|
||||||
use rustc_hir::{ConstArg, GenericArg, ParamName};
|
use rustc_hir::{ConstArg, GenericArg, ParamName};
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_session::config::nightly_options;
|
use rustc_session::config::nightly_options;
|
||||||
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
|
use rustc_session::lint::{builtin, BuiltinLintDiagnostics, LintBuffer};
|
||||||
use rustc_session::node_id::NodeMap;
|
use rustc_session::node_id::NodeMap;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::hygiene::ExpnId;
|
use rustc_span::hygiene::ExpnId;
|
||||||
|
|
|
@ -11,7 +11,7 @@ path = "lib.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
rustc_errors = { path = "../librustc_errors", package = "rustc_errors" }
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
rustc_error_codes = { path = "../librustc_error_codes" }
|
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||||
rustc_feature = { path = "../librustc_feature" }
|
rustc_feature = { path = "../librustc_feature" }
|
||||||
rustc_parse = { path = "../librustc_parse" }
|
rustc_parse = { path = "../librustc_parse" }
|
||||||
|
|
|
@ -14,35 +14,55 @@ where
|
||||||
Ok(mid) => mid,
|
Ok(mid) => mid,
|
||||||
Err(_) => return &[],
|
Err(_) => return &[],
|
||||||
};
|
};
|
||||||
|
let size = data.len();
|
||||||
|
|
||||||
// We get back *some* element with the given key -- so
|
// We get back *some* element with the given key -- so do
|
||||||
// search backwards to find the *first* one.
|
// a galloping search backwards to find the *first* one.
|
||||||
//
|
|
||||||
// (It'd be more efficient to use a "galloping" search
|
|
||||||
// here, but it's not really worth it for small-ish
|
|
||||||
// amounts of data.)
|
|
||||||
let mut start = mid;
|
let mut start = mid;
|
||||||
while start > 0 {
|
let mut previous = mid;
|
||||||
if key_fn(&data[start - 1]) == *key {
|
let mut step = 1;
|
||||||
start -= 1;
|
loop {
|
||||||
} else {
|
start = start.saturating_sub(step);
|
||||||
|
if start == 0 || key_fn(&data[start]) != *key {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
previous = start;
|
||||||
|
step *= 2;
|
||||||
|
}
|
||||||
|
step = previous - start;
|
||||||
|
while step > 1 {
|
||||||
|
let half = step / 2;
|
||||||
|
let mid = start + half;
|
||||||
|
if key_fn(&data[mid]) != *key {
|
||||||
|
start = mid;
|
||||||
|
}
|
||||||
|
step -= half;
|
||||||
|
}
|
||||||
|
// adjust by one if we have overshot
|
||||||
|
if start < size && key_fn(&data[start]) != *key {
|
||||||
|
start += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now search forward to find the *last* one.
|
// Now search forward to find the *last* one.
|
||||||
//
|
let mut end = mid;
|
||||||
// (It'd be more efficient to use a "galloping" search
|
let mut previous = mid;
|
||||||
// here, but it's not really worth it for small-ish
|
let mut step = 1;
|
||||||
// amounts of data.)
|
loop {
|
||||||
let mut end = mid + 1;
|
end = end.saturating_add(step).min(size);
|
||||||
let max = data.len();
|
if end == size || key_fn(&data[end]) != *key {
|
||||||
while end < max {
|
|
||||||
if key_fn(&data[end]) == *key {
|
|
||||||
end += 1;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
previous = end;
|
||||||
|
step *= 2;
|
||||||
|
}
|
||||||
|
step = end - previous;
|
||||||
|
while step > 1 {
|
||||||
|
let half = step / 2;
|
||||||
|
let mid = end - half;
|
||||||
|
if key_fn(&data[mid]) != *key {
|
||||||
|
end = mid;
|
||||||
|
}
|
||||||
|
step -= half;
|
||||||
}
|
}
|
||||||
|
|
||||||
&data[start..end]
|
&data[start..end]
|
||||||
|
|
|
@ -23,9 +23,7 @@ extern crate lazy_static;
|
||||||
|
|
||||||
pub extern crate rustc_plugin_impl as plugin;
|
pub extern crate rustc_plugin_impl as plugin;
|
||||||
|
|
||||||
//use rustc_resolve as resolve;
|
use rustc::lint::{Lint, LintId};
|
||||||
use rustc::lint;
|
|
||||||
use rustc::lint::Lint;
|
|
||||||
use rustc::middle::cstore::MetadataLoader;
|
use rustc::middle::cstore::MetadataLoader;
|
||||||
use rustc::session::config::nightly_options;
|
use rustc::session::config::nightly_options;
|
||||||
use rustc::session::config::{ErrorOutputType, Input, OutputType, PrintRequest};
|
use rustc::session::config::{ErrorOutputType, Input, OutputType, PrintRequest};
|
||||||
|
@ -41,6 +39,7 @@ use rustc_feature::{find_gated_cfg, UnstableFeatures};
|
||||||
use rustc_hir::def_id::LOCAL_CRATE;
|
use rustc_hir::def_id::LOCAL_CRATE;
|
||||||
use rustc_interface::util::get_builtin_codegen_backend;
|
use rustc_interface::util::get_builtin_codegen_backend;
|
||||||
use rustc_interface::{interface, Queries};
|
use rustc_interface::{interface, Queries};
|
||||||
|
use rustc_lint::LintStore;
|
||||||
use rustc_metadata::locator;
|
use rustc_metadata::locator;
|
||||||
use rustc_save_analysis as save;
|
use rustc_save_analysis as save;
|
||||||
use rustc_save_analysis::DumpHandler;
|
use rustc_save_analysis::DumpHandler;
|
||||||
|
@ -811,7 +810,7 @@ the command line flag directly.
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
|
fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
|
||||||
println!(
|
println!(
|
||||||
"
|
"
|
||||||
Available lint options:
|
Available lint options:
|
||||||
|
@ -832,8 +831,8 @@ Available lint options:
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sort_lint_groups(
|
fn sort_lint_groups(
|
||||||
lints: Vec<(&'static str, Vec<lint::LintId>, bool)>,
|
lints: Vec<(&'static str, Vec<LintId>, bool)>,
|
||||||
) -> Vec<(&'static str, Vec<lint::LintId>)> {
|
) -> Vec<(&'static str, Vec<LintId>)> {
|
||||||
let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
|
let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
|
||||||
lints.sort_by_key(|l| l.0);
|
lints.sort_by_key(|l| l.0);
|
||||||
lints
|
lints
|
||||||
|
@ -892,7 +891,7 @@ Available lint options:
|
||||||
println!(" {} {}", padded("----"), "---------");
|
println!(" {} {}", padded("----"), "---------");
|
||||||
println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings");
|
println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings");
|
||||||
|
|
||||||
let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
|
let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
|
||||||
for (name, to) in lints {
|
for (name, to) in lints {
|
||||||
let name = name.to_lowercase().replace("_", "-");
|
let name = name.to_lowercase().replace("_", "-");
|
||||||
let desc = to
|
let desc = to
|
||||||
|
|
|
@ -12,6 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_data_structures::OnDrop;
|
use rustc_data_structures::OnDrop;
|
||||||
use rustc_errors::registry::Registry;
|
use rustc_errors::registry::Registry;
|
||||||
|
use rustc_lint::LintStore;
|
||||||
use rustc_parse::new_parser_from_source_str;
|
use rustc_parse::new_parser_from_source_str;
|
||||||
use rustc_span::edition;
|
use rustc_span::edition;
|
||||||
use rustc_span::source_map::{FileLoader, FileName, SourceMap};
|
use rustc_span::source_map::{FileLoader, FileName, SourceMap};
|
||||||
|
@ -36,7 +37,7 @@ pub struct Compiler {
|
||||||
pub(crate) output_dir: Option<PathBuf>,
|
pub(crate) output_dir: Option<PathBuf>,
|
||||||
pub(crate) output_file: Option<PathBuf>,
|
pub(crate) output_file: Option<PathBuf>,
|
||||||
pub(crate) crate_name: Option<String>,
|
pub(crate) crate_name: Option<String>,
|
||||||
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
|
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
|
||||||
pub(crate) override_queries:
|
pub(crate) override_queries:
|
||||||
Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>,
|
Option<fn(&Session, &mut ty::query::Providers<'_>, &mut ty::query::Providers<'_>)>,
|
||||||
}
|
}
|
||||||
|
@ -136,7 +137,7 @@ pub struct Config {
|
||||||
///
|
///
|
||||||
/// Note that if you find a Some here you probably want to call that function in the new
|
/// Note that if you find a Some here you probably want to call that function in the new
|
||||||
/// function being registered.
|
/// function being registered.
|
||||||
pub register_lints: Option<Box<dyn Fn(&Session, &mut lint::LintStore) + Send + Sync>>,
|
pub register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
|
||||||
|
|
||||||
/// This is a callback from the driver that is called just after we have populated
|
/// This is a callback from the driver that is called just after we have populated
|
||||||
/// the list of queries.
|
/// the list of queries.
|
||||||
|
|
|
@ -27,6 +27,7 @@ use rustc_errors::PResult;
|
||||||
use rustc_expand::base::ExtCtxt;
|
use rustc_expand::base::ExtCtxt;
|
||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_incremental;
|
use rustc_incremental;
|
||||||
|
use rustc_lint::LintStore;
|
||||||
use rustc_mir as mir;
|
use rustc_mir as mir;
|
||||||
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
|
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
|
||||||
use rustc_passes::{self, hir_stats, layout_test};
|
use rustc_passes::{self, hir_stats, layout_test};
|
||||||
|
@ -100,7 +101,7 @@ declare_box_region_type!(
|
||||||
/// Returns `None` if we're aborting after handling -W help.
|
/// Returns `None` if we're aborting after handling -W help.
|
||||||
pub fn configure_and_expand(
|
pub fn configure_and_expand(
|
||||||
sess: Lrc<Session>,
|
sess: Lrc<Session>,
|
||||||
lint_store: Lrc<lint::LintStore>,
|
lint_store: Lrc<LintStore>,
|
||||||
metadata_loader: Box<MetadataLoaderDyn>,
|
metadata_loader: Box<MetadataLoaderDyn>,
|
||||||
krate: ast::Crate,
|
krate: ast::Crate,
|
||||||
crate_name: &str,
|
crate_name: &str,
|
||||||
|
@ -150,10 +151,10 @@ impl BoxedResolver {
|
||||||
pub fn register_plugins<'a>(
|
pub fn register_plugins<'a>(
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
metadata_loader: &'a dyn MetadataLoader,
|
metadata_loader: &'a dyn MetadataLoader,
|
||||||
register_lints: impl Fn(&Session, &mut lint::LintStore),
|
register_lints: impl Fn(&Session, &mut LintStore),
|
||||||
mut krate: ast::Crate,
|
mut krate: ast::Crate,
|
||||||
crate_name: &str,
|
crate_name: &str,
|
||||||
) -> Result<(ast::Crate, Lrc<lint::LintStore>)> {
|
) -> Result<(ast::Crate, Lrc<LintStore>)> {
|
||||||
krate = sess.time("attributes_injection", || {
|
krate = sess.time("attributes_injection", || {
|
||||||
rustc_builtin_macros::cmdline_attrs::inject(
|
rustc_builtin_macros::cmdline_attrs::inject(
|
||||||
krate,
|
krate,
|
||||||
|
@ -214,7 +215,7 @@ pub fn register_plugins<'a>(
|
||||||
|
|
||||||
fn configure_and_expand_inner<'a>(
|
fn configure_and_expand_inner<'a>(
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
lint_store: &'a lint::LintStore,
|
lint_store: &'a LintStore,
|
||||||
mut krate: ast::Crate,
|
mut krate: ast::Crate,
|
||||||
crate_name: &str,
|
crate_name: &str,
|
||||||
resolver_arenas: &'a ResolverArenas<'a>,
|
resolver_arenas: &'a ResolverArenas<'a>,
|
||||||
|
@ -420,7 +421,7 @@ fn configure_and_expand_inner<'a>(
|
||||||
|
|
||||||
pub fn lower_to_hir<'res, 'tcx>(
|
pub fn lower_to_hir<'res, 'tcx>(
|
||||||
sess: &'tcx Session,
|
sess: &'tcx Session,
|
||||||
lint_store: &lint::LintStore,
|
lint_store: &LintStore,
|
||||||
resolver: &'res mut Resolver<'_>,
|
resolver: &'res mut Resolver<'_>,
|
||||||
dep_graph: &'res DepGraph,
|
dep_graph: &'res DepGraph,
|
||||||
krate: &'res ast::Crate,
|
krate: &'res ast::Crate,
|
||||||
|
@ -705,7 +706,7 @@ impl<'tcx> QueryContext<'tcx> {
|
||||||
|
|
||||||
pub fn create_global_ctxt<'tcx>(
|
pub fn create_global_ctxt<'tcx>(
|
||||||
compiler: &'tcx Compiler,
|
compiler: &'tcx Compiler,
|
||||||
lint_store: Lrc<lint::LintStore>,
|
lint_store: Lrc<LintStore>,
|
||||||
hir_forest: &'tcx map::Forest<'tcx>,
|
hir_forest: &'tcx map::Forest<'tcx>,
|
||||||
mut resolver_outputs: ResolverOutputs,
|
mut resolver_outputs: ResolverOutputs,
|
||||||
outputs: OutputFilenames,
|
outputs: OutputFilenames,
|
||||||
|
|
|
@ -4,8 +4,6 @@ use crate::passes::{self, BoxedResolver, QueryContext};
|
||||||
use rustc::arena::Arena;
|
use rustc::arena::Arena;
|
||||||
use rustc::dep_graph::DepGraph;
|
use rustc::dep_graph::DepGraph;
|
||||||
use rustc::hir::map;
|
use rustc::hir::map;
|
||||||
use rustc::lint;
|
|
||||||
use rustc::lint::LintStore;
|
|
||||||
use rustc::session::config::{OutputFilenames, OutputType};
|
use rustc::session::config::{OutputFilenames, OutputType};
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use rustc::ty::steal::Steal;
|
use rustc::ty::steal::Steal;
|
||||||
|
@ -15,6 +13,7 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend;
|
||||||
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
|
use rustc_data_structures::sync::{Lrc, Once, WorkerLocal};
|
||||||
use rustc_hir::def_id::LOCAL_CRATE;
|
use rustc_hir::def_id::LOCAL_CRATE;
|
||||||
use rustc_incremental::DepGraphFuture;
|
use rustc_incremental::DepGraphFuture;
|
||||||
|
use rustc_lint::LintStore;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -133,7 +132,7 @@ impl<'tcx> Queries<'tcx> {
|
||||||
let crate_name = self.crate_name()?.peek().clone();
|
let crate_name = self.crate_name()?.peek().clone();
|
||||||
let krate = self.parse()?.take();
|
let krate = self.parse()?.take();
|
||||||
|
|
||||||
let empty: &(dyn Fn(&Session, &mut lint::LintStore) + Sync + Send) = &|_, _| {};
|
let empty: &(dyn Fn(&Session, &mut LintStore) + Sync + Send) = &|_, _| {};
|
||||||
let result = passes::register_plugins(
|
let result = passes::register_plugins(
|
||||||
self.session(),
|
self.session(),
|
||||||
&*self.codegen_backend().metadata_loader(),
|
&*self.codegen_backend().metadata_loader(),
|
||||||
|
|
|
@ -2,7 +2,7 @@ extern crate getopts;
|
||||||
|
|
||||||
use crate::interface::parse_cfgspecs;
|
use crate::interface::parse_cfgspecs;
|
||||||
|
|
||||||
use rustc::lint;
|
use rustc::lint::Level;
|
||||||
use rustc::middle::cstore;
|
use rustc::middle::cstore;
|
||||||
use rustc::session::config::{build_configuration, build_session_options, to_crate_config};
|
use rustc::session::config::{build_configuration, build_session_options, to_crate_config};
|
||||||
use rustc::session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
|
use rustc::session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
|
||||||
|
@ -186,24 +186,24 @@ fn test_lints_tracking_hash_different_values() {
|
||||||
let mut v3 = Options::default();
|
let mut v3 = Options::default();
|
||||||
|
|
||||||
v1.lint_opts = vec![
|
v1.lint_opts = vec![
|
||||||
(String::from("a"), lint::Allow),
|
(String::from("a"), Level::Allow),
|
||||||
(String::from("b"), lint::Warn),
|
(String::from("b"), Level::Warn),
|
||||||
(String::from("c"), lint::Deny),
|
(String::from("c"), Level::Deny),
|
||||||
(String::from("d"), lint::Forbid),
|
(String::from("d"), Level::Forbid),
|
||||||
];
|
];
|
||||||
|
|
||||||
v2.lint_opts = vec![
|
v2.lint_opts = vec![
|
||||||
(String::from("a"), lint::Allow),
|
(String::from("a"), Level::Allow),
|
||||||
(String::from("b"), lint::Warn),
|
(String::from("b"), Level::Warn),
|
||||||
(String::from("X"), lint::Deny),
|
(String::from("X"), Level::Deny),
|
||||||
(String::from("d"), lint::Forbid),
|
(String::from("d"), Level::Forbid),
|
||||||
];
|
];
|
||||||
|
|
||||||
v3.lint_opts = vec![
|
v3.lint_opts = vec![
|
||||||
(String::from("a"), lint::Allow),
|
(String::from("a"), Level::Allow),
|
||||||
(String::from("b"), lint::Warn),
|
(String::from("b"), Level::Warn),
|
||||||
(String::from("c"), lint::Forbid),
|
(String::from("c"), Level::Forbid),
|
||||||
(String::from("d"), lint::Deny),
|
(String::from("d"), Level::Deny),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
|
assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
|
||||||
|
@ -222,17 +222,17 @@ fn test_lints_tracking_hash_different_construction_order() {
|
||||||
let mut v2 = Options::default();
|
let mut v2 = Options::default();
|
||||||
|
|
||||||
v1.lint_opts = vec![
|
v1.lint_opts = vec![
|
||||||
(String::from("a"), lint::Allow),
|
(String::from("a"), Level::Allow),
|
||||||
(String::from("b"), lint::Warn),
|
(String::from("b"), Level::Warn),
|
||||||
(String::from("c"), lint::Deny),
|
(String::from("c"), Level::Deny),
|
||||||
(String::from("d"), lint::Forbid),
|
(String::from("d"), Level::Forbid),
|
||||||
];
|
];
|
||||||
|
|
||||||
v2.lint_opts = vec![
|
v2.lint_opts = vec![
|
||||||
(String::from("a"), lint::Allow),
|
(String::from("a"), Level::Allow),
|
||||||
(String::from("c"), lint::Deny),
|
(String::from("c"), Level::Deny),
|
||||||
(String::from("b"), lint::Warn),
|
(String::from("b"), Level::Warn),
|
||||||
(String::from("d"), lint::Forbid),
|
(String::from("d"), Level::Forbid),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
|
assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
|
||||||
|
|
|
@ -13,6 +13,7 @@ log = "0.4"
|
||||||
unicode-security = "0.0.2"
|
unicode-security = "0.0.2"
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_errors = { path = "../librustc_errors" }
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
|
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||||
rustc_hir = { path = "../librustc_hir" }
|
rustc_hir = { path = "../librustc_hir" }
|
||||||
rustc_target = { path = "../librustc_target" }
|
rustc_target = { path = "../librustc_target" }
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
use rustc::lint::{FutureIncompatibleInfo, LateContext, LateLintPass, LintContext};
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::ty::adjustment::{Adjust, Adjustment};
|
use rustc::ty::adjustment::{Adjust, Adjustment};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_session::lint::FutureIncompatibleInfo;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
//! If you define a new `LateLintPass`, you will also need to add it to the
|
//! If you define a new `LateLintPass`, you will also need to add it to the
|
||||||
//! `late_lint_methods!` invocation in `lib.rs`.
|
//! `late_lint_methods!` invocation in `lib.rs`.
|
||||||
|
|
||||||
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||||
use rustc::hir::map::Map;
|
use rustc::hir::map::Map;
|
||||||
use rustc::lint::{self, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
|
||||||
use rustc::traits::misc::can_type_implement_copy;
|
use rustc::traits::misc::can_type_implement_copy;
|
||||||
use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
|
use rustc::ty::{self, layout::VariantIdx, Ty, TyCtxt};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
@ -51,7 +51,7 @@ use log::debug;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
// hardwired lints from librustc
|
// hardwired lints from librustc
|
||||||
pub use lint::builtin::*;
|
pub use rustc_session::lint::builtin::*;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
WHILE_TRUE,
|
WHILE_TRUE,
|
||||||
|
|
|
@ -16,22 +16,23 @@
|
||||||
|
|
||||||
use self::TargetLint::*;
|
use self::TargetLint::*;
|
||||||
|
|
||||||
use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData};
|
use crate::levels::LintLevelsBuilder;
|
||||||
use crate::lint::levels::{LintLevelSets, LintLevelsBuilder};
|
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
|
||||||
use crate::lint::{EarlyLintPassObject, LateLintPassObject};
|
use rustc::hir::map::definitions::{DefPathData, DisambiguatedDefPathData};
|
||||||
use crate::middle::privacy::AccessLevels;
|
use rustc::lint::add_elided_lifetime_in_path_suggestion;
|
||||||
use crate::middle::stability;
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use crate::session::Session;
|
use rustc::middle::stability;
|
||||||
use crate::ty::layout::{LayoutError, LayoutOf, TyLayout};
|
use rustc::ty::layout::{LayoutError, LayoutOf, TyLayout};
|
||||||
use crate::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
|
use rustc::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_data_structures::sync;
|
use rustc_data_structures::sync;
|
||||||
use rustc_error_codes::*;
|
use rustc_error_codes::*;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{CrateNum, DefId};
|
use rustc_hir::def_id::{CrateNum, DefId};
|
||||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||||
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
|
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
|
||||||
|
use rustc_session::Session;
|
||||||
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
|
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::util::lev_distance::find_best_match_for_name;
|
use syntax::util::lev_distance::find_best_match_for_name;
|
||||||
|
@ -467,48 +468,6 @@ impl LintPassObject for EarlyLintPassObject {}
|
||||||
|
|
||||||
impl LintPassObject for LateLintPassObject {}
|
impl LintPassObject for LateLintPassObject {}
|
||||||
|
|
||||||
pub fn add_elided_lifetime_in_path_suggestion(
|
|
||||||
sess: &Session,
|
|
||||||
db: &mut DiagnosticBuilder<'_>,
|
|
||||||
n: usize,
|
|
||||||
path_span: Span,
|
|
||||||
incl_angl_brckt: bool,
|
|
||||||
insertion_span: Span,
|
|
||||||
anon_lts: String,
|
|
||||||
) {
|
|
||||||
let (replace_span, suggestion) = if incl_angl_brckt {
|
|
||||||
(insertion_span, anon_lts)
|
|
||||||
} else {
|
|
||||||
// When possible, prefer a suggestion that replaces the whole
|
|
||||||
// `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
|
|
||||||
// at a point (which makes for an ugly/confusing label)
|
|
||||||
if let Ok(snippet) = sess.source_map().span_to_snippet(path_span) {
|
|
||||||
// But our spans can get out of whack due to macros; if the place we think
|
|
||||||
// we want to insert `'_` isn't even within the path expression's span, we
|
|
||||||
// should bail out of making any suggestion rather than panicking on a
|
|
||||||
// subtract-with-overflow or string-slice-out-out-bounds (!)
|
|
||||||
// FIXME: can we do better?
|
|
||||||
if insertion_span.lo().0 < path_span.lo().0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
|
|
||||||
if insertion_index > snippet.len() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let (before, after) = snippet.split_at(insertion_index);
|
|
||||||
(path_span, format!("{}{}{}", before, anon_lts, after))
|
|
||||||
} else {
|
|
||||||
(insertion_span, anon_lts)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
db.span_suggestion(
|
|
||||||
replace_span,
|
|
||||||
&format!("indicate the anonymous lifetime{}", pluralize!(n)),
|
|
||||||
suggestion,
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LintContext: Sized {
|
pub trait LintContext: Sized {
|
||||||
type PassObject: LintPassObject;
|
type PassObject: LintPassObject;
|
||||||
|
|
||||||
|
@ -674,7 +633,7 @@ impl<'a> EarlyContext<'a> {
|
||||||
sess,
|
sess,
|
||||||
krate,
|
krate,
|
||||||
lint_store,
|
lint_store,
|
||||||
builder: LintLevelSets::builder(sess, warn_about_weird_lints, lint_store),
|
builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store),
|
||||||
buffered,
|
buffered,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,10 +14,9 @@
|
||||||
//! upon. As the ast is traversed, this keeps track of the current lint level
|
//! upon. As the ast is traversed, this keeps track of the current lint level
|
||||||
//! for all lint attributes.
|
//! for all lint attributes.
|
||||||
|
|
||||||
use rustc::lint::{EarlyContext, LintStore};
|
use crate::context::{EarlyContext, LintContext, LintStore};
|
||||||
use rustc::lint::{EarlyLintPass, EarlyLintPassObject};
|
use crate::passes::{EarlyLintPass, EarlyLintPassObject};
|
||||||
use rustc::lint::{LintContext, LintPass};
|
use rustc_session::lint::{LintBuffer, LintPass};
|
||||||
use rustc_session::lint::LintBuffer;
|
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
@ -291,7 +290,7 @@ macro_rules! early_lint_pass_impl {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
early_lint_methods!(early_lint_pass_impl, []);
|
crate::early_lint_methods!(early_lint_pass_impl, []);
|
||||||
|
|
||||||
fn early_lint_crate<T: EarlyLintPass>(
|
fn early_lint_crate<T: EarlyLintPass>(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
|
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
|
||||||
//! Clippy.
|
//! Clippy.
|
||||||
|
|
||||||
use crate::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
|
use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
|
|
@ -14,9 +14,8 @@
|
||||||
//! upon. As the ast is traversed, this keeps track of the current lint level
|
//! upon. As the ast is traversed, this keeps track of the current lint level
|
||||||
//! for all lint attributes.
|
//! for all lint attributes.
|
||||||
|
|
||||||
|
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
|
||||||
use rustc::hir::map::Map;
|
use rustc::hir::map::Map;
|
||||||
use rustc::lint::LateContext;
|
|
||||||
use rustc::lint::{LateLintPass, LateLintPassObject};
|
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
|
use rustc_data_structures::sync::{join, par_iter, ParallelIterator};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -29,8 +28,16 @@ use syntax::ast;
|
||||||
use syntax::walk_list;
|
use syntax::walk_list;
|
||||||
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
use std::any::Any;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
|
/// Extract the `LintStore` from the query context.
|
||||||
|
/// This function exists because we've erased `LintStore` as `dyn Any` in the context.
|
||||||
|
crate fn unerased_lint_store<'tcx>(tcx: TyCtxt<'tcx>) -> &'tcx LintStore {
|
||||||
|
let store: &dyn Any = &*tcx.lint_store;
|
||||||
|
store.downcast_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
|
macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({
|
||||||
$cx.pass.$f(&$cx.context, $($args),*);
|
$cx.pass.$f(&$cx.context, $($args),*);
|
||||||
}) }
|
}) }
|
||||||
|
@ -342,7 +349,7 @@ macro_rules! late_lint_pass_impl {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
|
crate::late_lint_methods!(late_lint_pass_impl, [], ['tcx]);
|
||||||
|
|
||||||
fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -356,7 +363,7 @@ fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
||||||
tables: &ty::TypeckTables::empty(None),
|
tables: &ty::TypeckTables::empty(None),
|
||||||
param_env: ty::ParamEnv::empty(),
|
param_env: ty::ParamEnv::empty(),
|
||||||
access_levels,
|
access_levels,
|
||||||
lint_store: &tcx.lint_store,
|
lint_store: unerased_lint_store(tcx),
|
||||||
last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
|
last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(),
|
||||||
generics: None,
|
generics: None,
|
||||||
only_module: true,
|
only_module: true,
|
||||||
|
@ -386,7 +393,7 @@ pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(
|
||||||
late_lint_mod_pass(tcx, module_def_id, builtin_lints);
|
late_lint_mod_pass(tcx, module_def_id, builtin_lints);
|
||||||
|
|
||||||
let mut passes: Vec<_> =
|
let mut passes: Vec<_> =
|
||||||
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
|
unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
|
||||||
|
|
||||||
if !passes.is_empty() {
|
if !passes.is_empty() {
|
||||||
late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
|
late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] });
|
||||||
|
@ -403,7 +410,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
|
||||||
tables: &ty::TypeckTables::empty(None),
|
tables: &ty::TypeckTables::empty(None),
|
||||||
param_env: ty::ParamEnv::empty(),
|
param_env: ty::ParamEnv::empty(),
|
||||||
access_levels,
|
access_levels,
|
||||||
lint_store: &tcx.lint_store,
|
lint_store: unerased_lint_store(tcx),
|
||||||
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
|
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
|
||||||
generics: None,
|
generics: None,
|
||||||
only_module: false,
|
only_module: false,
|
||||||
|
@ -424,7 +431,7 @@ fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
|
fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) {
|
||||||
let mut passes = tcx.lint_store.late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
|
let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::<Vec<_>>();
|
||||||
|
|
||||||
if !tcx.sess.opts.debugging_opts.no_interleave_lints {
|
if !tcx.sess.opts.debugging_opts.no_interleave_lints {
|
||||||
if !passes.is_empty() {
|
if !passes.is_empty() {
|
||||||
|
@ -443,7 +450,7 @@ fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, b
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut passes: Vec<_> =
|
let mut passes: Vec<_> =
|
||||||
tcx.lint_store.late_module_passes.iter().map(|pass| (pass)()).collect();
|
unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect();
|
||||||
|
|
||||||
for pass in &mut passes {
|
for pass in &mut passes {
|
||||||
tcx.sess
|
tcx.sess
|
||||||
|
|
|
@ -1,22 +1,33 @@
|
||||||
|
use crate::context::{CheckLintNameResult, LintStore};
|
||||||
|
use crate::late::unerased_lint_store;
|
||||||
use rustc::hir::map::Map;
|
use rustc::hir::map::Map;
|
||||||
use rustc::lint::{LintLevelMap, LintLevelSets, LintLevelsBuilder, LintStore};
|
use rustc::lint::struct_lint_level;
|
||||||
|
use rustc::lint::{LintLevelMap, LintLevelSets, LintSet, LintSource};
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_error_codes::*;
|
||||||
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
|
use rustc_hir::hir_id::HirId;
|
||||||
use rustc_hir::intravisit;
|
use rustc_hir::intravisit;
|
||||||
|
use rustc_session::lint::{builtin, Level, Lint};
|
||||||
|
use rustc_session::Session;
|
||||||
|
use rustc_span::{sym, MultiSpan, Symbol};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
use syntax::attr;
|
||||||
|
use syntax::print::pprust;
|
||||||
|
use syntax::sess::feature_err;
|
||||||
|
use syntax::unwrap_or;
|
||||||
|
|
||||||
pub use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintId};
|
use std::cmp;
|
||||||
|
|
||||||
fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
|
fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
|
||||||
assert_eq!(cnum, LOCAL_CRATE);
|
assert_eq!(cnum, LOCAL_CRATE);
|
||||||
let store = &tcx.lint_store;
|
let store = unerased_lint_store(tcx);
|
||||||
let mut builder = LintLevelMapBuilder {
|
let levels = LintLevelsBuilder::new(tcx.sess, false, &store);
|
||||||
levels: LintLevelSets::builder(tcx.sess, false, &store),
|
let mut builder = LintLevelMapBuilder { levels, tcx, store };
|
||||||
tcx: tcx,
|
|
||||||
store: store,
|
|
||||||
};
|
|
||||||
let krate = tcx.hir().krate();
|
let krate = tcx.hir().krate();
|
||||||
|
|
||||||
let push = builder.levels.push(&krate.attrs, &store);
|
let push = builder.levels.push(&krate.attrs, &store);
|
||||||
|
@ -30,6 +41,378 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> &LintLevelMap {
|
||||||
tcx.arena.alloc(builder.levels.build_map())
|
tcx.arena.alloc(builder.levels.build_map())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct LintLevelsBuilder<'a> {
|
||||||
|
sess: &'a Session,
|
||||||
|
sets: LintLevelSets,
|
||||||
|
id_to_set: FxHashMap<HirId, u32>,
|
||||||
|
cur: u32,
|
||||||
|
warn_about_weird_lints: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BuilderPush {
|
||||||
|
prev: u32,
|
||||||
|
pub changed: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LintLevelsBuilder<'a> {
|
||||||
|
pub fn new(sess: &'a Session, warn_about_weird_lints: bool, store: &LintStore) -> Self {
|
||||||
|
let mut builder = LintLevelsBuilder {
|
||||||
|
sess,
|
||||||
|
sets: LintLevelSets::new(),
|
||||||
|
cur: 0,
|
||||||
|
id_to_set: Default::default(),
|
||||||
|
warn_about_weird_lints,
|
||||||
|
};
|
||||||
|
builder.process_command_line(sess, store);
|
||||||
|
assert_eq!(builder.sets.list.len(), 1);
|
||||||
|
builder
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
|
||||||
|
let mut specs = FxHashMap::default();
|
||||||
|
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
|
||||||
|
|
||||||
|
for &(ref lint_name, level) in &sess.opts.lint_opts {
|
||||||
|
store.check_lint_name_cmdline(sess, &lint_name, level);
|
||||||
|
|
||||||
|
// If the cap is less than this specified level, e.g., if we've got
|
||||||
|
// `--cap-lints allow` but we've also got `-D foo` then we ignore
|
||||||
|
// this specification as the lint cap will set it to allow anyway.
|
||||||
|
let level = cmp::min(level, self.sets.lint_cap);
|
||||||
|
|
||||||
|
let lint_flag_val = Symbol::intern(lint_name);
|
||||||
|
let ids = match store.find_lints(&lint_name) {
|
||||||
|
Ok(ids) => ids,
|
||||||
|
Err(_) => continue, // errors handled in check_lint_name_cmdline above
|
||||||
|
};
|
||||||
|
for id in ids {
|
||||||
|
let src = LintSource::CommandLine(lint_flag_val);
|
||||||
|
specs.insert(id, (level, src));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sets.list.push(LintSet::CommandLine { specs });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pushes a list of AST lint attributes onto this context.
|
||||||
|
///
|
||||||
|
/// This function will return a `BuilderPush` object which should be passed
|
||||||
|
/// to `pop` when this scope for the attributes provided is exited.
|
||||||
|
///
|
||||||
|
/// This function will perform a number of tasks:
|
||||||
|
///
|
||||||
|
/// * It'll validate all lint-related attributes in `attrs`
|
||||||
|
/// * It'll mark all lint-related attributes as used
|
||||||
|
/// * Lint levels will be updated based on the attributes provided
|
||||||
|
/// * Lint attributes are validated, e.g., a #[forbid] can't be switched to
|
||||||
|
/// #[allow]
|
||||||
|
///
|
||||||
|
/// Don't forget to call `pop`!
|
||||||
|
pub fn push(&mut self, attrs: &[ast::Attribute], store: &LintStore) -> BuilderPush {
|
||||||
|
let mut specs = FxHashMap::default();
|
||||||
|
let sess = self.sess;
|
||||||
|
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
|
||||||
|
for attr in attrs {
|
||||||
|
let level = match Level::from_symbol(attr.name_or_empty()) {
|
||||||
|
None => continue,
|
||||||
|
Some(lvl) => lvl,
|
||||||
|
};
|
||||||
|
|
||||||
|
let meta = unwrap_or!(attr.meta(), continue);
|
||||||
|
attr::mark_used(attr);
|
||||||
|
|
||||||
|
let mut metas = unwrap_or!(meta.meta_item_list(), continue);
|
||||||
|
|
||||||
|
if metas.is_empty() {
|
||||||
|
// FIXME (#55112): issue unused-attributes lint for `#[level()]`
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before processing the lint names, look for a reason (RFC 2383)
|
||||||
|
// at the end.
|
||||||
|
let mut reason = None;
|
||||||
|
let tail_li = &metas[metas.len() - 1];
|
||||||
|
if let Some(item) = tail_li.meta_item() {
|
||||||
|
match item.kind {
|
||||||
|
ast::MetaItemKind::Word => {} // actual lint names handled later
|
||||||
|
ast::MetaItemKind::NameValue(ref name_value) => {
|
||||||
|
if item.path == sym::reason {
|
||||||
|
// found reason, reslice meta list to exclude it
|
||||||
|
metas = &metas[0..metas.len() - 1];
|
||||||
|
// FIXME (#55112): issue unused-attributes lint if we thereby
|
||||||
|
// don't have any lint names (`#[level(reason = "foo")]`)
|
||||||
|
if let ast::LitKind::Str(rationale, _) = name_value.kind {
|
||||||
|
if !self.sess.features_untracked().lint_reasons {
|
||||||
|
feature_err(
|
||||||
|
&self.sess.parse_sess,
|
||||||
|
sym::lint_reasons,
|
||||||
|
item.span,
|
||||||
|
"lint reasons are experimental",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
reason = Some(rationale);
|
||||||
|
} else {
|
||||||
|
bad_attr(name_value.span)
|
||||||
|
.span_label(name_value.span, "reason must be a string literal")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bad_attr(item.span)
|
||||||
|
.span_label(item.span, "bad attribute argument")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::MetaItemKind::List(_) => {
|
||||||
|
bad_attr(item.span).span_label(item.span, "bad attribute argument").emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for li in metas {
|
||||||
|
let meta_item = match li.meta_item() {
|
||||||
|
Some(meta_item) if meta_item.is_word() => meta_item,
|
||||||
|
_ => {
|
||||||
|
let sp = li.span();
|
||||||
|
let mut err = bad_attr(sp);
|
||||||
|
let mut add_label = true;
|
||||||
|
if let Some(item) = li.meta_item() {
|
||||||
|
if let ast::MetaItemKind::NameValue(_) = item.kind {
|
||||||
|
if item.path == sym::reason {
|
||||||
|
err.span_label(sp, "reason in lint attribute must come last");
|
||||||
|
add_label = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if add_label {
|
||||||
|
err.span_label(sp, "bad attribute argument");
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let tool_name = if meta_item.path.segments.len() > 1 {
|
||||||
|
let tool_ident = meta_item.path.segments[0].ident;
|
||||||
|
if !attr::is_known_lint_tool(tool_ident) {
|
||||||
|
struct_span_err!(
|
||||||
|
sess,
|
||||||
|
tool_ident.span,
|
||||||
|
E0710,
|
||||||
|
"an unknown tool name found in scoped lint: `{}`",
|
||||||
|
pprust::path_to_string(&meta_item.path),
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(tool_ident.name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let name = meta_item.path.segments.last().expect("empty lint name").ident.name;
|
||||||
|
match store.check_lint_name(&name.as_str(), tool_name) {
|
||||||
|
CheckLintNameResult::Ok(ids) => {
|
||||||
|
let src = LintSource::Node(name, li.span(), reason);
|
||||||
|
for id in ids {
|
||||||
|
specs.insert(*id, (level, src));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckLintNameResult::Tool(result) => {
|
||||||
|
match result {
|
||||||
|
Ok(ids) => {
|
||||||
|
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
|
||||||
|
let src = LintSource::Node(
|
||||||
|
Symbol::intern(complete_name),
|
||||||
|
li.span(),
|
||||||
|
reason,
|
||||||
|
);
|
||||||
|
for id in ids {
|
||||||
|
specs.insert(*id, (level, src));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err((Some(ids), new_lint_name)) => {
|
||||||
|
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
||||||
|
let (lvl, src) =
|
||||||
|
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
|
||||||
|
let msg = format!(
|
||||||
|
"lint name `{}` is deprecated \
|
||||||
|
and may not have an effect in the future. \
|
||||||
|
Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
|
||||||
|
name
|
||||||
|
);
|
||||||
|
struct_lint_level(
|
||||||
|
self.sess,
|
||||||
|
lint,
|
||||||
|
lvl,
|
||||||
|
src,
|
||||||
|
Some(li.span().into()),
|
||||||
|
&msg,
|
||||||
|
)
|
||||||
|
.span_suggestion(
|
||||||
|
li.span(),
|
||||||
|
"change it to",
|
||||||
|
new_lint_name.to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
|
||||||
|
let src = LintSource::Node(
|
||||||
|
Symbol::intern(&new_lint_name),
|
||||||
|
li.span(),
|
||||||
|
reason,
|
||||||
|
);
|
||||||
|
for id in ids {
|
||||||
|
specs.insert(*id, (level, src));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err((None, _)) => {
|
||||||
|
// If Tool(Err(None, _)) is returned, then either the lint does not
|
||||||
|
// exist in the tool or the code was not compiled with the tool and
|
||||||
|
// therefore the lint was never added to the `LintStore`. To detect
|
||||||
|
// this is the responsibility of the lint tool.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ if !self.warn_about_weird_lints => {}
|
||||||
|
|
||||||
|
CheckLintNameResult::Warning(msg, renamed) => {
|
||||||
|
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
|
||||||
|
let (level, src) =
|
||||||
|
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
|
||||||
|
let mut err = struct_lint_level(
|
||||||
|
self.sess,
|
||||||
|
lint,
|
||||||
|
level,
|
||||||
|
src,
|
||||||
|
Some(li.span().into()),
|
||||||
|
&msg,
|
||||||
|
);
|
||||||
|
if let Some(new_name) = renamed {
|
||||||
|
err.span_suggestion(
|
||||||
|
li.span(),
|
||||||
|
"use the new name",
|
||||||
|
new_name,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
CheckLintNameResult::NoLint(suggestion) => {
|
||||||
|
let lint = builtin::UNKNOWN_LINTS;
|
||||||
|
let (level, src) =
|
||||||
|
self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
|
||||||
|
let msg = format!("unknown lint: `{}`", name);
|
||||||
|
let mut db = struct_lint_level(
|
||||||
|
self.sess,
|
||||||
|
lint,
|
||||||
|
level,
|
||||||
|
src,
|
||||||
|
Some(li.span().into()),
|
||||||
|
&msg,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(suggestion) = suggestion {
|
||||||
|
db.span_suggestion(
|
||||||
|
li.span(),
|
||||||
|
"did you mean",
|
||||||
|
suggestion.to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
db.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, &(level, ref src)) in specs.iter() {
|
||||||
|
if level == Level::Forbid {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) {
|
||||||
|
(Some(Level::Forbid), src) => src,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
let forbidden_lint_name = match forbid_src {
|
||||||
|
LintSource::Default => id.to_string(),
|
||||||
|
LintSource::Node(name, _, _) => name.to_string(),
|
||||||
|
LintSource::CommandLine(name) => name.to_string(),
|
||||||
|
};
|
||||||
|
let (lint_attr_name, lint_attr_span) = match *src {
|
||||||
|
LintSource::Node(name, span, _) => (name, span),
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
let mut diag_builder = struct_span_err!(
|
||||||
|
self.sess,
|
||||||
|
lint_attr_span,
|
||||||
|
E0453,
|
||||||
|
"{}({}) overruled by outer forbid({})",
|
||||||
|
level.as_str(),
|
||||||
|
lint_attr_name,
|
||||||
|
forbidden_lint_name
|
||||||
|
);
|
||||||
|
diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
|
||||||
|
match forbid_src {
|
||||||
|
LintSource::Default => {}
|
||||||
|
LintSource::Node(_, forbid_source_span, reason) => {
|
||||||
|
diag_builder.span_label(forbid_source_span, "`forbid` level set here");
|
||||||
|
if let Some(rationale) = reason {
|
||||||
|
diag_builder.note(&rationale.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LintSource::CommandLine(_) => {
|
||||||
|
diag_builder.note("`forbid` lint level was set on command line");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diag_builder.emit();
|
||||||
|
// don't set a separate error for every lint in the group
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev = self.cur;
|
||||||
|
if specs.len() > 0 {
|
||||||
|
self.cur = self.sets.list.len() as u32;
|
||||||
|
self.sets.list.push(LintSet::Node { specs: specs, parent: prev });
|
||||||
|
}
|
||||||
|
|
||||||
|
BuilderPush { prev: prev, changed: prev != self.cur }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called after `push` when the scope of a set of attributes are exited.
|
||||||
|
pub fn pop(&mut self, push: BuilderPush) {
|
||||||
|
self.cur = push.prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Used to emit a lint-related diagnostic based on the current state of
|
||||||
|
/// this lint context.
|
||||||
|
pub fn struct_lint(
|
||||||
|
&self,
|
||||||
|
lint: &'static Lint,
|
||||||
|
span: Option<MultiSpan>,
|
||||||
|
msg: &str,
|
||||||
|
) -> DiagnosticBuilder<'a> {
|
||||||
|
let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
|
||||||
|
struct_lint_level(self.sess, lint, level, src, span, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers the ID provided with the current set of lints stored in
|
||||||
|
/// this context.
|
||||||
|
pub fn register_id(&mut self, id: HirId) {
|
||||||
|
self.id_to_set.insert(id, self.cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> LintLevelSets {
|
||||||
|
self.sets
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_map(self) -> LintLevelMap {
|
||||||
|
LintLevelMap { sets: self.sets, id_to_set: self.id_to_set }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct LintLevelMapBuilder<'a, 'tcx> {
|
struct LintLevelMapBuilder<'a, 'tcx> {
|
||||||
levels: LintLevelsBuilder<'tcx>,
|
levels: LintLevelsBuilder<'tcx>,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|
|
@ -1,9 +1,25 @@
|
||||||
//! # Lints in the Rust compiler
|
//! Lints, aka compiler warnings.
|
||||||
//!
|
//!
|
||||||
//! This currently only contains the definitions and implementations
|
//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
|
||||||
//! of most of the lints that `rustc` supports directly, it does not
|
//! want to enforce, but might reasonably want to permit as well, on a
|
||||||
//! contain the infrastructure for defining/registering lints. That is
|
//! module-by-module basis. They contrast with static constraints enforced by
|
||||||
//! available in `rustc::lint` and `rustc_driver::plugin` respectively.
|
//! other phases of the compiler, which are generally required to hold in order
|
||||||
|
//! to compile the program at all.
|
||||||
|
//!
|
||||||
|
//! Most lints can be written as `LintPass` instances. These run after
|
||||||
|
//! all other analyses. The `LintPass`es built into rustc are defined
|
||||||
|
//! within `rustc_session::lint::builtin`,
|
||||||
|
//! which has further comments on how to add such a lint.
|
||||||
|
//! rustc can also load user-defined lint plugins via the plugin mechanism.
|
||||||
|
//!
|
||||||
|
//! Some of rustc's lints are defined elsewhere in the compiler and work by
|
||||||
|
//! calling `add_lint()` on the overall `Session` object. This works when
|
||||||
|
//! it happens before the main lint pass, which emits the lints stored by
|
||||||
|
//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
|
||||||
|
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
||||||
|
//! in `context.rs`.
|
||||||
|
//!
|
||||||
|
//! Some code also exists in `rustc_session::lint`, `rustc::lint`.
|
||||||
//!
|
//!
|
||||||
//! ## Note
|
//! ## Note
|
||||||
//!
|
//!
|
||||||
|
@ -14,6 +30,8 @@
|
||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
#![feature(crate_visibility_modifier)]
|
||||||
|
#![feature(never_type)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![recursion_limit = "256"]
|
#![recursion_limit = "256"]
|
||||||
|
|
||||||
|
@ -24,45 +42,47 @@ extern crate rustc_session;
|
||||||
|
|
||||||
mod array_into_iter;
|
mod array_into_iter;
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
|
mod context;
|
||||||
mod early;
|
mod early;
|
||||||
|
mod internal;
|
||||||
mod late;
|
mod late;
|
||||||
mod levels;
|
mod levels;
|
||||||
mod non_ascii_idents;
|
mod non_ascii_idents;
|
||||||
mod nonstandard_style;
|
mod nonstandard_style;
|
||||||
|
mod passes;
|
||||||
mod redundant_semicolon;
|
mod redundant_semicolon;
|
||||||
mod types;
|
mod types;
|
||||||
mod unused;
|
mod unused;
|
||||||
|
|
||||||
use rustc::lint;
|
|
||||||
use rustc::lint::builtin::{
|
|
||||||
BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
|
|
||||||
INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
|
|
||||||
};
|
|
||||||
use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::TyCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_session::lint::{LintArray, LintPass};
|
use rustc_session::lint::builtin::{
|
||||||
|
BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
|
||||||
|
INTRA_DOC_LINK_RESOLUTION_FAILURE, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
|
||||||
|
};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
use lint::LintId;
|
|
||||||
|
|
||||||
use array_into_iter::ArrayIntoIter;
|
use array_into_iter::ArrayIntoIter;
|
||||||
use builtin::*;
|
use builtin::*;
|
||||||
|
use internal::*;
|
||||||
use non_ascii_idents::*;
|
use non_ascii_idents::*;
|
||||||
use nonstandard_style::*;
|
use nonstandard_style::*;
|
||||||
use redundant_semicolon::*;
|
use redundant_semicolon::*;
|
||||||
use rustc::lint::internal::*;
|
|
||||||
use types::*;
|
use types::*;
|
||||||
use unused::*;
|
use unused::*;
|
||||||
|
|
||||||
/// Useful for other parts of the compiler.
|
/// Useful for other parts of the compiler / Clippy.
|
||||||
pub use builtin::SoftLints;
|
pub use builtin::SoftLints;
|
||||||
|
pub use context::{EarlyContext, LateContext, LintContext, LintStore};
|
||||||
pub use early::check_ast_crate;
|
pub use early::check_ast_crate;
|
||||||
pub use late::check_crate;
|
pub use late::check_crate;
|
||||||
|
pub use passes::{EarlyLintPass, LateLintPass};
|
||||||
|
pub use rustc_session::lint::Level::{self, *};
|
||||||
|
pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
|
||||||
|
pub use rustc_session::lint::{LintArray, LintPass};
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers<'_>) {
|
pub fn provide(providers: &mut Providers<'_>) {
|
||||||
levels::provide(providers);
|
levels::provide(providers);
|
||||||
|
@ -179,8 +199,8 @@ late_lint_passes!(declare_combined_late_pass, [pub BuiltinCombinedLateLintPass])
|
||||||
|
|
||||||
late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);
|
late_lint_mod_passes!(declare_combined_late_pass, [BuiltinCombinedModuleLateLintPass]);
|
||||||
|
|
||||||
pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::LintStore {
|
pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> LintStore {
|
||||||
let mut lint_store = lint::LintStore::new();
|
let mut lint_store = LintStore::new();
|
||||||
|
|
||||||
register_builtins(&mut lint_store, no_interleave_lints);
|
register_builtins(&mut lint_store, no_interleave_lints);
|
||||||
if internal_lints {
|
if internal_lints {
|
||||||
|
@ -193,7 +213,7 @@ pub fn new_lint_store(no_interleave_lints: bool, internal_lints: bool) -> lint::
|
||||||
/// Tell the `LintStore` about all the built-in lints (the ones
|
/// Tell the `LintStore` about all the built-in lints (the ones
|
||||||
/// defined in this crate and the ones defined in
|
/// defined in this crate and the ones defined in
|
||||||
/// `rustc::lint::builtin`).
|
/// `rustc::lint::builtin`).
|
||||||
fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
|
fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
|
||||||
macro_rules! add_lint_group {
|
macro_rules! add_lint_group {
|
||||||
($name:expr, $($lint:ident),*) => (
|
($name:expr, $($lint:ident),*) => (
|
||||||
store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
|
store.register_group(false, $name, None, vec![$(LintId::of($lint)),*]);
|
||||||
|
@ -390,7 +410,7 @@ fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) {
|
||||||
store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
|
store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_internals(store: &mut lint::LintStore) {
|
fn register_internals(store: &mut LintStore) {
|
||||||
store.register_lints(&DefaultHashTypes::get_lints());
|
store.register_lints(&DefaultHashTypes::get_lints());
|
||||||
store.register_early_pass(|| box DefaultHashTypes::new());
|
store.register_early_pass(|| box DefaultHashTypes::new());
|
||||||
store.register_lints(&LintPassImpl::get_lints());
|
store.register_lints(&LintPassImpl::get_lints());
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintContext};
|
use crate::{EarlyContext, EarlyLintPass, LintContext};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
|
|
@ -1,47 +1,12 @@
|
||||||
//! Lints, aka compiler warnings.
|
use crate::context::{EarlyContext, LateContext};
|
||||||
//!
|
|
||||||
//! A 'lint' check is a kind of miscellaneous constraint that a user _might_
|
|
||||||
//! want to enforce, but might reasonably want to permit as well, on a
|
|
||||||
//! module-by-module basis. They contrast with static constraints enforced by
|
|
||||||
//! other phases of the compiler, which are generally required to hold in order
|
|
||||||
//! to compile the program at all.
|
|
||||||
//!
|
|
||||||
//! Most lints can be written as `LintPass` instances. These run after
|
|
||||||
//! all other analyses. The `LintPass`es built into rustc are defined
|
|
||||||
//! within `builtin.rs`, which has further comments on how to add such a lint.
|
|
||||||
//! rustc can also load user-defined lint plugins via the plugin mechanism.
|
|
||||||
//!
|
|
||||||
//! Some of rustc's lints are defined elsewhere in the compiler and work by
|
|
||||||
//! calling `add_lint()` on the overall `Session` object. This works when
|
|
||||||
//! it happens before the main lint pass, which emits the lints stored by
|
|
||||||
//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
|
|
||||||
//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
|
|
||||||
//! in `context.rs`.
|
|
||||||
|
|
||||||
pub use self::Level::*;
|
|
||||||
pub use self::LintSource::*;
|
|
||||||
|
|
||||||
use crate::ty::TyCtxt;
|
|
||||||
use rustc_data_structures::sync;
|
use rustc_data_structures::sync;
|
||||||
use rustc_errors::{DiagnosticBuilder, DiagnosticId};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_session::lint::builtin::HardwiredLints;
|
use rustc_session::lint::builtin::HardwiredLints;
|
||||||
use rustc_session::{DiagnosticMessageId, Session};
|
use rustc_session::lint::LintPass;
|
||||||
use rustc_span::hygiene::MacroKind;
|
|
||||||
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
|
|
||||||
use rustc_span::symbol::Symbol;
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
pub use crate::lint::context::{
|
|
||||||
add_elided_lifetime_in_path_suggestion, CheckLintNameResult, EarlyContext, LateContext,
|
|
||||||
LintContext, LintStore,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use rustc_session::lint::builtin;
|
|
||||||
pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Level, Lint, LintId};
|
|
||||||
pub use rustc_session::lint::{LintArray, LintPass};
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! late_lint_methods {
|
macro_rules! late_lint_methods {
|
||||||
($macro:path, $args:tt, [$hir:tt]) => (
|
($macro:path, $args:tt, [$hir:tt]) => (
|
||||||
|
@ -176,6 +141,7 @@ macro_rules! declare_combined_late_lint_pass {
|
||||||
expand_combined_late_lint_pass_methods!([$($passes),*], $methods);
|
expand_combined_late_lint_pass_methods!([$($passes),*], $methods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::lint_pass_impl_without_macro)]
|
||||||
impl LintPass for $name {
|
impl LintPass for $name {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
panic!()
|
panic!()
|
||||||
|
@ -303,6 +269,7 @@ macro_rules! declare_combined_early_lint_pass {
|
||||||
expand_combined_early_lint_pass_methods!([$($passes),*], $methods);
|
expand_combined_early_lint_pass_methods!([$($passes),*], $methods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(rustc::lint_pass_impl_without_macro)]
|
||||||
impl LintPass for $name {
|
impl LintPass for $name {
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
panic!()
|
panic!()
|
||||||
|
@ -315,190 +282,3 @@ macro_rules! declare_combined_early_lint_pass {
|
||||||
pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>;
|
pub type EarlyLintPassObject = Box<dyn EarlyLintPass + sync::Send + sync::Sync + 'static>;
|
||||||
pub type LateLintPassObject =
|
pub type LateLintPassObject =
|
||||||
Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>;
|
Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>;
|
||||||
|
|
||||||
/// How a lint level was set.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
|
|
||||||
pub enum LintSource {
|
|
||||||
/// Lint is at the default level as declared
|
|
||||||
/// in rustc or a plugin.
|
|
||||||
Default,
|
|
||||||
|
|
||||||
/// Lint level was set by an attribute.
|
|
||||||
Node(ast::Name, Span, Option<Symbol> /* RFC 2383 reason */),
|
|
||||||
|
|
||||||
/// Lint level was set by a command-line flag.
|
|
||||||
CommandLine(Symbol),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type LevelSource = (Level, LintSource);
|
|
||||||
|
|
||||||
mod context;
|
|
||||||
pub mod internal;
|
|
||||||
mod levels;
|
|
||||||
|
|
||||||
pub use self::levels::{LintLevelMap, LintLevelSets, LintLevelsBuilder};
|
|
||||||
|
|
||||||
pub fn struct_lint_level<'a>(
|
|
||||||
sess: &'a Session,
|
|
||||||
lint: &'static Lint,
|
|
||||||
level: Level,
|
|
||||||
src: LintSource,
|
|
||||||
span: Option<MultiSpan>,
|
|
||||||
msg: &str,
|
|
||||||
) -> DiagnosticBuilder<'a> {
|
|
||||||
let mut err = match (level, span) {
|
|
||||||
(Level::Allow, _) => return sess.diagnostic().struct_dummy(),
|
|
||||||
(Level::Warn, Some(span)) => sess.struct_span_warn(span, msg),
|
|
||||||
(Level::Warn, None) => sess.struct_warn(msg),
|
|
||||||
(Level::Deny, Some(span)) | (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg),
|
|
||||||
(Level::Deny, None) | (Level::Forbid, None) => sess.struct_err(msg),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check for future incompatibility lints and issue a stronger warning.
|
|
||||||
let lint_id = LintId::of(lint);
|
|
||||||
let future_incompatible = lint.future_incompatible;
|
|
||||||
|
|
||||||
// If this code originates in a foreign macro, aka something that this crate
|
|
||||||
// did not itself author, then it's likely that there's nothing this crate
|
|
||||||
// can do about it. We probably want to skip the lint entirely.
|
|
||||||
if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) {
|
|
||||||
// Any suggestions made here are likely to be incorrect, so anything we
|
|
||||||
// emit shouldn't be automatically fixed by rustfix.
|
|
||||||
err.allow_suggestions(false);
|
|
||||||
|
|
||||||
// If this is a future incompatible lint it'll become a hard error, so
|
|
||||||
// we have to emit *something*. Also allow lints to whitelist themselves
|
|
||||||
// on a case-by-case basis for emission in a foreign macro.
|
|
||||||
if future_incompatible.is_none() && !lint.report_in_external_macro {
|
|
||||||
err.cancel();
|
|
||||||
// Don't continue further, since we don't want to have
|
|
||||||
// `diag_span_note_once` called for a diagnostic that isn't emitted.
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = lint.name_lower();
|
|
||||||
match src {
|
|
||||||
LintSource::Default => {
|
|
||||||
sess.diag_note_once(
|
|
||||||
&mut err,
|
|
||||||
DiagnosticMessageId::from(lint),
|
|
||||||
&format!("`#[{}({})]` on by default", level.as_str(), name),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
LintSource::CommandLine(lint_flag_val) => {
|
|
||||||
let flag = match level {
|
|
||||||
Level::Warn => "-W",
|
|
||||||
Level::Deny => "-D",
|
|
||||||
Level::Forbid => "-F",
|
|
||||||
Level::Allow => panic!(),
|
|
||||||
};
|
|
||||||
let hyphen_case_lint_name = name.replace("_", "-");
|
|
||||||
if lint_flag_val.as_str() == name {
|
|
||||||
sess.diag_note_once(
|
|
||||||
&mut err,
|
|
||||||
DiagnosticMessageId::from(lint),
|
|
||||||
&format!(
|
|
||||||
"requested on the command line with `{} {}`",
|
|
||||||
flag, hyphen_case_lint_name
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-");
|
|
||||||
sess.diag_note_once(
|
|
||||||
&mut err,
|
|
||||||
DiagnosticMessageId::from(lint),
|
|
||||||
&format!(
|
|
||||||
"`{} {}` implied by `{} {}`",
|
|
||||||
flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LintSource::Node(lint_attr_name, src, reason) => {
|
|
||||||
if let Some(rationale) = reason {
|
|
||||||
err.note(&rationale.as_str());
|
|
||||||
}
|
|
||||||
sess.diag_span_note_once(
|
|
||||||
&mut err,
|
|
||||||
DiagnosticMessageId::from(lint),
|
|
||||||
src,
|
|
||||||
"lint level defined here",
|
|
||||||
);
|
|
||||||
if lint_attr_name.as_str() != name {
|
|
||||||
let level_str = level.as_str();
|
|
||||||
sess.diag_note_once(
|
|
||||||
&mut err,
|
|
||||||
DiagnosticMessageId::from(lint),
|
|
||||||
&format!(
|
|
||||||
"`#[{}({})]` implied by `#[{}({})]`",
|
|
||||||
level_str, name, level_str, lint_attr_name
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err.code(DiagnosticId::Lint(name));
|
|
||||||
|
|
||||||
if let Some(future_incompatible) = future_incompatible {
|
|
||||||
const STANDARD_MESSAGE: &str = "this was previously accepted by the compiler but is being phased out; \
|
|
||||||
it will become a hard error";
|
|
||||||
|
|
||||||
let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) {
|
|
||||||
"once this method is added to the standard library, \
|
|
||||||
the ambiguity may cause an error or change in behavior!"
|
|
||||||
.to_owned()
|
|
||||||
} else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) {
|
|
||||||
"this borrowing pattern was not meant to be accepted, \
|
|
||||||
and may become a hard error in the future"
|
|
||||||
.to_owned()
|
|
||||||
} else if let Some(edition) = future_incompatible.edition {
|
|
||||||
format!("{} in the {} edition!", STANDARD_MESSAGE, edition)
|
|
||||||
} else {
|
|
||||||
format!("{} in a future release!", STANDARD_MESSAGE)
|
|
||||||
};
|
|
||||||
let citation = format!("for more information, see {}", future_incompatible.reference);
|
|
||||||
err.warn(&explanation);
|
|
||||||
err.note(&citation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn maybe_lint_level_root(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
|
||||||
let attrs = tcx.hir().attrs(id);
|
|
||||||
attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether `span` originates in a foreign crate's external macro.
|
|
||||||
///
|
|
||||||
/// This is used to test whether a lint should not even begin to figure out whether it should
|
|
||||||
/// be reported on the current node.
|
|
||||||
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
|
|
||||||
let expn_data = span.ctxt().outer_expn_data();
|
|
||||||
match expn_data.kind {
|
|
||||||
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false,
|
|
||||||
ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external"
|
|
||||||
ExpnKind::Macro(MacroKind::Bang, _) => {
|
|
||||||
if expn_data.def_site.is_dummy() {
|
|
||||||
// Dummy span for the `def_site` means it's an external macro.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
match sess.source_map().span_to_snippet(expn_data.def_site) {
|
|
||||||
Ok(code) => !code.starts_with("macro_rules"),
|
|
||||||
// No snippet means external macro or compiler-builtin expansion.
|
|
||||||
Err(_) => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExpnKind::Macro(..) => true, // definitely a plugin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if `span` originates in a derive-macro's expansion.
|
|
||||||
pub fn in_derive_expansion(span: Span) -> bool {
|
|
||||||
if let ExpnKind::Macro(MacroKind::Derive, _) = span.ctxt().outer_expn_data().kind {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintContext};
|
use crate::{EarlyContext, EarlyLintPass, LintContext};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use syntax::ast::{ExprKind, Stmt, StmtKind};
|
use syntax::ast::{ExprKind, Stmt, StmtKind};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use rustc::lint::{LateContext, LateLintPass, LintContext};
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
use rustc::mir::interpret::{sign_extend, truncate};
|
use rustc::mir::interpret::{sign_extend, truncate};
|
||||||
use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx};
|
use rustc::ty::layout::{self, IntegerExt, LayoutOf, SizeSkeleton, VariantIdx};
|
||||||
use rustc::ty::subst::SubstsRef;
|
use rustc::ty::subst::SubstsRef;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use rustc::lint::builtin::UNUSED_ATTRIBUTES;
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||||
use rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
|
||||||
use rustc::ty::adjustment;
|
use rustc::ty::adjustment;
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
@ -8,6 +7,7 @@ use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::{kw, sym};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span};
|
||||||
|
|
|
@ -637,17 +637,17 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||||
if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) {
|
if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) {
|
||||||
tcx.unsafe_derive_on_repr_packed(impl_def_id);
|
tcx.unsafe_derive_on_repr_packed(impl_def_id);
|
||||||
} else {
|
} else {
|
||||||
tcx.lint_node_note(
|
tcx.struct_span_lint_hir(
|
||||||
SAFE_PACKED_BORROWS,
|
SAFE_PACKED_BORROWS,
|
||||||
lint_hir_id,
|
lint_hir_id,
|
||||||
source_info.span,
|
source_info.span,
|
||||||
&format!(
|
&format!(
|
||||||
"{} is unsafe and requires unsafe function or block \
|
"{} is unsafe and requires unsafe function or block (error E0133)",
|
||||||
(error E0133)",
|
|
||||||
description
|
description
|
||||||
),
|
),
|
||||||
&details.as_str(),
|
)
|
||||||
);
|
.note(&details.as_str())
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_error_codes::*;
|
use rustc_error_codes::*;
|
||||||
use rustc_errors::{pluralize, struct_span_err};
|
use rustc_errors::{pluralize, struct_span_err};
|
||||||
use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
|
use rustc_errors::{Applicability, DiagnosticBuilder, Handler, PResult};
|
||||||
|
use rustc_span::source_map::Spanned;
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
|
use rustc_span::{MultiSpan, Span, SpanSnippetError, DUMMY_SP};
|
||||||
use syntax::ast::{
|
use syntax::ast::{
|
||||||
|
@ -491,6 +492,58 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
|
||||||
|
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
|
||||||
|
/// parenthesising the leftmost comparison.
|
||||||
|
fn attempt_chained_comparison_suggestion(
|
||||||
|
&mut self,
|
||||||
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
|
inner_op: &Expr,
|
||||||
|
outer_op: &Spanned<AssocOp>,
|
||||||
|
) {
|
||||||
|
if let ExprKind::Binary(op, ref l1, ref r1) = inner_op.kind {
|
||||||
|
match (op.node, &outer_op.node) {
|
||||||
|
// `x < y < z` and friends.
|
||||||
|
(BinOpKind::Lt, AssocOp::Less) | (BinOpKind::Lt, AssocOp::LessEqual) |
|
||||||
|
(BinOpKind::Le, AssocOp::LessEqual) | (BinOpKind::Le, AssocOp::Less) |
|
||||||
|
// `x > y > z` and friends.
|
||||||
|
(BinOpKind::Gt, AssocOp::Greater) | (BinOpKind::Gt, AssocOp::GreaterEqual) |
|
||||||
|
(BinOpKind::Ge, AssocOp::GreaterEqual) | (BinOpKind::Ge, AssocOp::Greater) => {
|
||||||
|
let expr_to_str = |e: &Expr| {
|
||||||
|
self.span_to_snippet(e.span)
|
||||||
|
.unwrap_or_else(|_| pprust::expr_to_string(&e))
|
||||||
|
};
|
||||||
|
err.span_suggestion(
|
||||||
|
inner_op.span.to(outer_op.span),
|
||||||
|
"split the comparison into two...",
|
||||||
|
format!(
|
||||||
|
"{} {} {} && {} {}",
|
||||||
|
expr_to_str(&l1),
|
||||||
|
op.node.to_string(),
|
||||||
|
expr_to_str(&r1),
|
||||||
|
expr_to_str(&r1),
|
||||||
|
outer_op.node.to_ast_binop().unwrap().to_string(),
|
||||||
|
),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
err.span_suggestion(
|
||||||
|
inner_op.span.to(outer_op.span),
|
||||||
|
"...or parenthesize one of the comparisons",
|
||||||
|
format!(
|
||||||
|
"({} {} {}) {}",
|
||||||
|
expr_to_str(&l1),
|
||||||
|
op.node.to_string(),
|
||||||
|
expr_to_str(&r1),
|
||||||
|
outer_op.node.to_ast_binop().unwrap().to_string(),
|
||||||
|
),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Produces an error if comparison operators are chained (RFC #558).
|
/// Produces an error if comparison operators are chained (RFC #558).
|
||||||
/// We only need to check the LHS, not the RHS, because all comparison ops have same
|
/// We only need to check the LHS, not the RHS, because all comparison ops have same
|
||||||
/// precedence (see `fn precedence`) and are left-associative (see `fn fixity`).
|
/// precedence (see `fn precedence`) and are left-associative (see `fn fixity`).
|
||||||
|
@ -506,27 +559,31 @@ impl<'a> Parser<'a> {
|
||||||
/// / \
|
/// / \
|
||||||
/// inner_op r2
|
/// inner_op r2
|
||||||
/// / \
|
/// / \
|
||||||
/// l1 r1
|
/// l1 r1
|
||||||
pub(super) fn check_no_chained_comparison(
|
pub(super) fn check_no_chained_comparison(
|
||||||
&mut self,
|
&mut self,
|
||||||
lhs: &Expr,
|
inner_op: &Expr,
|
||||||
outer_op: &AssocOp,
|
outer_op: &Spanned<AssocOp>,
|
||||||
) -> PResult<'a, Option<P<Expr>>> {
|
) -> PResult<'a, Option<P<Expr>>> {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
outer_op.is_comparison(),
|
outer_op.node.is_comparison(),
|
||||||
"check_no_chained_comparison: {:?} is not comparison",
|
"check_no_chained_comparison: {:?} is not comparison",
|
||||||
outer_op,
|
outer_op.node,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mk_err_expr =
|
let mk_err_expr =
|
||||||
|this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new())));
|
|this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err, AttrVec::new())));
|
||||||
|
|
||||||
match lhs.kind {
|
match inner_op.kind {
|
||||||
ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
|
ExprKind::Binary(op, _, _) if op.node.is_comparison() => {
|
||||||
// Respan to include both operators.
|
// Respan to include both operators.
|
||||||
let op_span = op.span.to(self.prev_span);
|
let op_span = op.span.to(self.prev_span);
|
||||||
let mut err = self
|
let mut err =
|
||||||
.struct_span_err(op_span, "chained comparison operators require parentheses");
|
self.struct_span_err(op_span, "comparison operators cannot be chained");
|
||||||
|
|
||||||
|
// If it looks like a genuine attempt to chain operators (as opposed to a
|
||||||
|
// misformatted turbofish, for instance), suggest a correct form.
|
||||||
|
self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
|
||||||
|
|
||||||
let suggest = |err: &mut DiagnosticBuilder<'_>| {
|
let suggest = |err: &mut DiagnosticBuilder<'_>| {
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
|
@ -538,12 +595,12 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if op.node == BinOpKind::Lt &&
|
if op.node == BinOpKind::Lt &&
|
||||||
*outer_op == AssocOp::Less || // Include `<` to provide this recommendation
|
outer_op.node == AssocOp::Less || // Include `<` to provide this recommendation
|
||||||
*outer_op == AssocOp::Greater
|
outer_op.node == AssocOp::Greater
|
||||||
// even in a case like the following:
|
// even in a case like the following:
|
||||||
{
|
{
|
||||||
// Foo<Bar<Baz<Qux, ()>>>
|
// Foo<Bar<Baz<Qux, ()>>>
|
||||||
if *outer_op == AssocOp::Less {
|
if outer_op.node == AssocOp::Less {
|
||||||
let snapshot = self.clone();
|
let snapshot = self.clone();
|
||||||
self.bump();
|
self.bump();
|
||||||
// So far we have parsed `foo<bar<`, consume the rest of the type args.
|
// So far we have parsed `foo<bar<`, consume the rest of the type args.
|
||||||
|
@ -575,7 +632,7 @@ impl<'a> Parser<'a> {
|
||||||
// FIXME: actually check that the two expressions in the binop are
|
// FIXME: actually check that the two expressions in the binop are
|
||||||
// paths and resynthesize new fn call expression instead of using
|
// paths and resynthesize new fn call expression instead of using
|
||||||
// `ExprKind::Err` placeholder.
|
// `ExprKind::Err` placeholder.
|
||||||
mk_err_expr(self, lhs.span.to(self.prev_span))
|
mk_err_expr(self, inner_op.span.to(self.prev_span))
|
||||||
}
|
}
|
||||||
Err(mut expr_err) => {
|
Err(mut expr_err) => {
|
||||||
expr_err.cancel();
|
expr_err.cancel();
|
||||||
|
@ -597,7 +654,7 @@ impl<'a> Parser<'a> {
|
||||||
// FIXME: actually check that the two expressions in the binop are
|
// FIXME: actually check that the two expressions in the binop are
|
||||||
// paths and resynthesize new fn call expression instead of using
|
// paths and resynthesize new fn call expression instead of using
|
||||||
// `ExprKind::Err` placeholder.
|
// `ExprKind::Err` placeholder.
|
||||||
mk_err_expr(self, lhs.span.to(self.prev_span))
|
mk_err_expr(self, inner_op.span.to(self.prev_span))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use super::{SemiColonMode, SeqSep, TokenExpectType};
|
||||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||||
|
|
||||||
use rustc_errors::{Applicability, PResult};
|
use rustc_errors::{Applicability, PResult};
|
||||||
use rustc_span::source_map::{self, Span};
|
use rustc_span::source_map::{self, Span, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Symbol};
|
use rustc_span::symbol::{kw, sym, Symbol};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use syntax::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, DUMMY_NODE_ID};
|
use syntax::ast::{self, AttrStyle, AttrVec, CaptureBy, Field, Ident, Lit, DUMMY_NODE_ID};
|
||||||
|
@ -180,17 +180,17 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let cur_op_span = self.token.span;
|
let cur_op_span = self.token.span;
|
||||||
let restrictions = if op.is_assign_like() {
|
let restrictions = if op.node.is_assign_like() {
|
||||||
self.restrictions & Restrictions::NO_STRUCT_LITERAL
|
self.restrictions & Restrictions::NO_STRUCT_LITERAL
|
||||||
} else {
|
} else {
|
||||||
self.restrictions
|
self.restrictions
|
||||||
};
|
};
|
||||||
let prec = op.precedence();
|
let prec = op.node.precedence();
|
||||||
if prec < min_prec {
|
if prec < min_prec {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Check for deprecated `...` syntax
|
// Check for deprecated `...` syntax
|
||||||
if self.token == token::DotDotDot && op == AssocOp::DotDotEq {
|
if self.token == token::DotDotDot && op.node == AssocOp::DotDotEq {
|
||||||
self.err_dotdotdot_syntax(self.token.span);
|
self.err_dotdotdot_syntax(self.token.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,11 +199,12 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.bump();
|
self.bump();
|
||||||
if op.is_comparison() {
|
if op.node.is_comparison() {
|
||||||
if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
|
if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? {
|
||||||
return Ok(expr);
|
return Ok(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let op = op.node;
|
||||||
// Special cases:
|
// Special cases:
|
||||||
if op == AssocOp::As {
|
if op == AssocOp::As {
|
||||||
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
|
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
|
||||||
|
@ -297,7 +298,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
|
fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
|
||||||
match (self.expr_is_complete(lhs), self.check_assoc_op()) {
|
match (self.expr_is_complete(lhs), self.check_assoc_op().map(|op| op.node)) {
|
||||||
// Semi-statement forms are odd:
|
// Semi-statement forms are odd:
|
||||||
// See https://github.com/rust-lang/rust/issues/29071
|
// See https://github.com/rust-lang/rust/issues/29071
|
||||||
(true, None) => false,
|
(true, None) => false,
|
||||||
|
@ -342,19 +343,22 @@ impl<'a> Parser<'a> {
|
||||||
/// The method does not advance the current token.
|
/// The method does not advance the current token.
|
||||||
///
|
///
|
||||||
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
|
/// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively.
|
||||||
fn check_assoc_op(&self) -> Option<AssocOp> {
|
fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> {
|
||||||
match (AssocOp::from_token(&self.token), &self.token.kind) {
|
Some(Spanned {
|
||||||
(op @ Some(_), _) => op,
|
node: match (AssocOp::from_token(&self.token), &self.token.kind) {
|
||||||
(None, token::Ident(sym::and, false)) => {
|
(Some(op), _) => op,
|
||||||
self.error_bad_logical_op("and", "&&", "conjunction");
|
(None, token::Ident(sym::and, false)) => {
|
||||||
Some(AssocOp::LAnd)
|
self.error_bad_logical_op("and", "&&", "conjunction");
|
||||||
}
|
AssocOp::LAnd
|
||||||
(None, token::Ident(sym::or, false)) => {
|
}
|
||||||
self.error_bad_logical_op("or", "||", "disjunction");
|
(None, token::Ident(sym::or, false)) => {
|
||||||
Some(AssocOp::LOr)
|
self.error_bad_logical_op("or", "||", "disjunction");
|
||||||
}
|
AssocOp::LOr
|
||||||
_ => None,
|
}
|
||||||
}
|
_ => return None,
|
||||||
|
},
|
||||||
|
span: self.token.span,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error on `and` and `or` suggesting `&&` and `||` respectively.
|
/// Error on `and` and `or` suggesting `&&` and `||` respectively.
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
// from live codes are live, and everything else is dead.
|
// from live codes are live, and everything else is dead.
|
||||||
|
|
||||||
use rustc::hir::map::Map;
|
use rustc::hir::map::Map;
|
||||||
use rustc::lint;
|
|
||||||
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use rustc::middle::privacy;
|
use rustc::middle::privacy;
|
||||||
use rustc::ty::{self, DefIdTree, TyCtxt};
|
use rustc::ty::{self, DefIdTree, TyCtxt};
|
||||||
|
@ -14,6 +13,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||||
use rustc_hir::{Node, PatKind, TyKind};
|
use rustc_hir::{Node, PatKind, TyKind};
|
||||||
|
use rustc_session::lint;
|
||||||
|
|
||||||
use rustc_span;
|
use rustc_span;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
|
|
|
@ -1513,13 +1513,16 @@ impl<'tcx> Liveness<'_, 'tcx> {
|
||||||
if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() };
|
if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() };
|
||||||
|
|
||||||
if is_assigned {
|
if is_assigned {
|
||||||
self.ir.tcx.lint_hir_note(
|
self.ir
|
||||||
lint::builtin::UNUSED_VARIABLES,
|
.tcx
|
||||||
hir_id,
|
.struct_span_lint_hir(
|
||||||
spans,
|
lint::builtin::UNUSED_VARIABLES,
|
||||||
&format!("variable `{}` is assigned to, but never used", name),
|
hir_id,
|
||||||
&format!("consider using `_{}` instead", name),
|
spans,
|
||||||
);
|
&format!("variable `{}` is assigned to, but never used", name),
|
||||||
|
)
|
||||||
|
.note(&format!("consider using `_{}` instead", name))
|
||||||
|
.emit();
|
||||||
} else {
|
} else {
|
||||||
let mut err = self.ir.tcx.struct_span_lint_hir(
|
let mut err = self.ir.tcx.struct_span_lint_hir(
|
||||||
lint::builtin::UNUSED_VARIABLES,
|
lint::builtin::UNUSED_VARIABLES,
|
||||||
|
|
|
@ -14,6 +14,7 @@ doctest = false
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_errors = { path = "../librustc_errors" }
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
rustc_hir = { path = "../librustc_hir" }
|
rustc_hir = { path = "../librustc_hir" }
|
||||||
|
rustc_lint = { path = "../librustc_lint" }
|
||||||
rustc_metadata = { path = "../librustc_metadata" }
|
rustc_metadata = { path = "../librustc_metadata" }
|
||||||
syntax = { path = "../libsyntax" }
|
syntax = { path = "../libsyntax" }
|
||||||
rustc_span = { path = "../librustc_span" }
|
rustc_span = { path = "../librustc_span" }
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
|
|
||||||
use rustc::lint::LintStore;
|
use rustc_lint::LintStore;
|
||||||
|
|
||||||
pub mod build;
|
pub mod build;
|
||||||
pub mod load;
|
pub mod load;
|
||||||
|
|
|
@ -308,6 +308,11 @@ impl Span {
|
||||||
self.ctxt() != SyntaxContext::root()
|
self.ctxt() != SyntaxContext::root()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `span` originates in a derive-macro's expansion.
|
||||||
|
pub fn in_derive_expansion(self) -> bool {
|
||||||
|
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
|
pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
|
||||||
Span::new(lo, hi, SyntaxContext::root())
|
Span::new(lo, hi, SyntaxContext::root())
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use rustc::lint;
|
|
||||||
use rustc::middle::cstore::CrateStore;
|
use rustc::middle::cstore::CrateStore;
|
||||||
use rustc::middle::privacy::AccessLevels;
|
use rustc::middle::privacy::AccessLevels;
|
||||||
use rustc::session::config::ErrorOutputType;
|
use rustc::session::config::ErrorOutputType;
|
||||||
|
@ -14,6 +13,7 @@ use rustc_hir::HirId;
|
||||||
use rustc_interface::interface;
|
use rustc_interface::interface;
|
||||||
use rustc_lint;
|
use rustc_lint;
|
||||||
use rustc_resolve as resolve;
|
use rustc_resolve as resolve;
|
||||||
|
use rustc_session::lint;
|
||||||
|
|
||||||
use rustc_errors::emitter::{Emitter, EmitterWriter};
|
use rustc_errors::emitter::{Emitter, EmitterWriter};
|
||||||
use rustc_errors::json::JsonEmitter;
|
use rustc_errors::json::JsonEmitter;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
#![feature(set_stdio)]
|
#![feature(set_stdio)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
#![feature(vec_remove_item)]
|
||||||
#![feature(ptr_offset_from)]
|
#![feature(ptr_offset_from)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
|
@ -35,6 +36,7 @@ extern crate rustc_metadata;
|
||||||
extern crate rustc_mir;
|
extern crate rustc_mir;
|
||||||
extern crate rustc_parse;
|
extern crate rustc_parse;
|
||||||
extern crate rustc_resolve;
|
extern crate rustc_resolve;
|
||||||
|
extern crate rustc_session;
|
||||||
extern crate rustc_span as rustc_span;
|
extern crate rustc_span as rustc_span;
|
||||||
extern crate rustc_target;
|
extern crate rustc_target;
|
||||||
extern crate rustc_typeck;
|
extern crate rustc_typeck;
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#![feature(box_syntax, plugin, plugin_registrar, rustc_private)]
|
#![feature(box_syntax, plugin, plugin_registrar, rustc_private)]
|
||||||
#![crate_type = "dylib"]
|
#![crate_type = "dylib"]
|
||||||
|
|
||||||
#[macro_use] extern crate rustc;
|
|
||||||
#[macro_use] extern crate rustc_session;
|
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
|
#[macro_use] extern crate rustc_lint;
|
||||||
|
#[macro_use] extern crate rustc_session;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
use rustc_hir::intravisit;
|
use rustc_hir::intravisit;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::Node;
|
use rustc_hir::Node;
|
||||||
use rustc::lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
|
use rustc_lint::{LateContext, LintPass, LintArray, LateLintPass, LintContext};
|
||||||
use rustc_driver::plugin::Registry;
|
use rustc_driver::plugin::Registry;
|
||||||
use rustc_span::source_map;
|
use rustc_span::source_map;
|
||||||
use syntax::print::pprust;
|
use syntax::print::pprust;
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
#![feature(plugin_registrar, rustc_private)]
|
#![feature(plugin_registrar, rustc_private)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#[macro_use] extern crate rustc;
|
|
||||||
#[macro_use] extern crate rustc_session;
|
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
|
#[macro_use] extern crate rustc_lint;
|
||||||
|
#[macro_use] extern crate rustc_session;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass};
|
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass};
|
||||||
use rustc_driver::plugin::Registry;
|
use rustc_driver::plugin::Registry;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
#![feature(plugin_registrar, rustc_private)]
|
#![feature(plugin_registrar, rustc_private)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
|
|
||||||
#[macro_use] extern crate rustc;
|
|
||||||
#[macro_use] extern crate rustc_session;
|
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
|
#[macro_use] extern crate rustc_lint;
|
||||||
|
#[macro_use] extern crate rustc_session;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray};
|
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray};
|
||||||
use rustc_driver::plugin::Registry;
|
use rustc_driver::plugin::Registry;
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
#![feature(box_syntax, rustc_private)]
|
#![feature(box_syntax, rustc_private)]
|
||||||
|
|
||||||
// Load rustc as a plugin to get macros.
|
// Load rustc as a plugin to get macros.
|
||||||
#[macro_use] extern crate rustc;
|
|
||||||
#[macro_use] extern crate rustc_session;
|
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
|
#[macro_use] extern crate rustc_lint;
|
||||||
|
#[macro_use] extern crate rustc_session;
|
||||||
|
|
||||||
use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
|
use rustc_lint::{LateContext, LintContext, LintPass, LateLintPass, LintArray, LintId};
|
||||||
use rustc_driver::plugin::Registry;
|
use rustc_driver::plugin::Registry;
|
||||||
|
|
||||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
// Load rustc as a plugin to get macros
|
// Load rustc as a plugin to get macros
|
||||||
#[macro_use] extern crate rustc;
|
|
||||||
#[macro_use] extern crate rustc_session;
|
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
|
#[macro_use] extern crate rustc_lint;
|
||||||
|
#[macro_use] extern crate rustc_session;
|
||||||
|
|
||||||
use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
|
use rustc_lint::{EarlyContext, LintContext, LintPass, EarlyLintPass, LintArray};
|
||||||
use rustc_driver::plugin::Registry;
|
use rustc_driver::plugin::Registry;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
// Load rustc as a plugin to get macros
|
// Load rustc as a plugin to get macros
|
||||||
#[macro_use] extern crate rustc;
|
|
||||||
#[macro_use] extern crate rustc_session;
|
|
||||||
extern crate rustc_driver;
|
extern crate rustc_driver;
|
||||||
|
#[macro_use] extern crate rustc_lint;
|
||||||
|
#[macro_use] extern crate rustc_session;
|
||||||
|
|
||||||
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
|
use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass, LintId};
|
||||||
use rustc_driver::plugin::Registry;
|
use rustc_driver::plugin::Registry;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
|
declare_tool_lint!(pub clippy::TEST_LINT, Warn, "Warn about stuff");
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
(0..13).collect<Vec<i32>>();
|
(0..13).collect<Vec<i32>>();
|
||||||
//~^ ERROR chained comparison
|
//~^ ERROR comparison operators cannot be chained
|
||||||
Vec<i32>::new();
|
Vec<i32>::new();
|
||||||
//~^ ERROR chained comparison
|
//~^ ERROR comparison operators cannot be chained
|
||||||
(0..13).collect<Vec<i32>();
|
(0..13).collect<Vec<i32>();
|
||||||
//~^ ERROR chained comparison
|
//~^ ERROR comparison operators cannot be chained
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,23 @@
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/issue-40396.rs:2:20
|
--> $DIR/issue-40396.rs:2:20
|
||||||
|
|
|
|
||||||
LL | (0..13).collect<Vec<i32>>();
|
LL | (0..13).collect<Vec<i32>>();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | (0..13).collect < Vec && Vec <i32>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | ((0..13).collect < Vec) <i32>>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: use `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | (0..13).collect::<Vec<i32>>();
|
LL | (0..13).collect::<Vec<i32>>();
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/issue-40396.rs:4:8
|
--> $DIR/issue-40396.rs:4:8
|
||||||
|
|
|
|
||||||
LL | Vec<i32>::new();
|
LL | Vec<i32>::new();
|
||||||
|
@ -20,12 +28,20 @@ help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
LL | Vec::<i32>::new();
|
LL | Vec::<i32>::new();
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/issue-40396.rs:6:20
|
--> $DIR/issue-40396.rs:6:20
|
||||||
|
|
|
|
||||||
LL | (0..13).collect<Vec<i32>();
|
LL | (0..13).collect<Vec<i32>();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | (0..13).collect < Vec && Vec <i32>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | ((0..13).collect < Vec) <i32>();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
help: use `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | (0..13).collect::<Vec<i32>();
|
LL | (0..13).collect::<Vec<i32>();
|
||||||
|
|
40
src/test/ui/parser/chained-comparison-suggestion.rs
Normal file
40
src/test/ui/parser/chained-comparison-suggestion.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Check that we get nice suggestions when attempting a chained comparison.
|
||||||
|
|
||||||
|
fn comp1() {
|
||||||
|
1 < 2 <= 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp2() {
|
||||||
|
1 < 2 < 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp3() {
|
||||||
|
1 <= 2 < 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp4() {
|
||||||
|
1 <= 2 <= 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp5() {
|
||||||
|
1 > 2 >= 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp6() {
|
||||||
|
1 > 2 > 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp7() {
|
||||||
|
1 >= 2 > 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
}
|
||||||
|
|
||||||
|
fn comp8() {
|
||||||
|
1 >= 2 >= 3; //~ ERROR comparison operators cannot be chained
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
159
src/test/ui/parser/chained-comparison-suggestion.stderr
Normal file
159
src/test/ui/parser/chained-comparison-suggestion.stderr
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:4:7
|
||||||
|
|
|
||||||
|
LL | 1 < 2 <= 3;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 < 2 && 2 <= 3;
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 < 2) <= 3;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:9:7
|
||||||
|
|
|
||||||
|
LL | 1 < 2 < 3;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
= help: or use `(...)` if you meant to specify fn arguments
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 < 2 && 2 < 3;
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 < 2) < 3;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:13:7
|
||||||
|
|
|
||||||
|
LL | 1 <= 2 < 3;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 <= 2 && 2 < 3;
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 <= 2) < 3;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:18:7
|
||||||
|
|
|
||||||
|
LL | 1 <= 2 <= 3;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 <= 2 && 2 <= 3;
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 <= 2) <= 3;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:23:7
|
||||||
|
|
|
||||||
|
LL | 1 > 2 >= 3;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 > 2 && 2 >= 3;
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 > 2) >= 3;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:28:7
|
||||||
|
|
|
||||||
|
LL | 1 > 2 > 3;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
= help: or use `(...)` if you meant to specify fn arguments
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 > 2 && 2 > 3;
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 > 2) > 3;
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:32:7
|
||||||
|
|
|
||||||
|
LL | 1 >= 2 > 3;
|
||||||
|
| ^^^^^^
|
||||||
|
|
|
||||||
|
= help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
= help: or use `(...)` if you meant to specify fn arguments
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 >= 2 && 2 > 3;
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 >= 2) > 3;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: comparison operators cannot be chained
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:36:7
|
||||||
|
|
|
||||||
|
LL | 1 >= 2 >= 3;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | 1 >= 2 && 2 >= 3;
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (1 >= 2) >= 3;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:4:14
|
||||||
|
|
|
||||||
|
LL | 1 < 2 <= 3;
|
||||||
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:13:14
|
||||||
|
|
|
||||||
|
LL | 1 <= 2 < 3;
|
||||||
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:18:15
|
||||||
|
|
|
||||||
|
LL | 1 <= 2 <= 3;
|
||||||
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:23:14
|
||||||
|
|
|
||||||
|
LL | 1 > 2 >= 3;
|
||||||
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/chained-comparison-suggestion.rs:36:15
|
||||||
|
|
|
||||||
|
LL | 1 >= 2 >= 3;
|
||||||
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
|
error: aborting due to 13 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
|
@ -3,24 +3,26 @@ struct X;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
false == false == false;
|
false == false == false;
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR comparison operators cannot be chained
|
||||||
|
|
||||||
false == 0 < 2;
|
false == 0 < 2;
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR comparison operators cannot be chained
|
||||||
//~| ERROR mismatched types
|
//~| ERROR mismatched types
|
||||||
//~| ERROR mismatched types
|
//~| ERROR mismatched types
|
||||||
|
|
||||||
f<X>();
|
f<X>();
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR comparison operators cannot be chained
|
||||||
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
||||||
f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR comparison operators cannot be chained
|
||||||
|
//~| HELP split the comparison into two...
|
||||||
|
//~| ...or parenthesize one of the comparisons
|
||||||
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
||||||
use std::convert::identity;
|
use std::convert::identity;
|
||||||
let _ = identity<u8>;
|
let _ = identity<u8>;
|
||||||
//~^ ERROR chained comparison operators require parentheses
|
//~^ ERROR comparison operators cannot be chained
|
||||||
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
//~| HELP use `::<...>` instead of `<...>` to specify type arguments
|
||||||
//~| HELP or use `(...)` if you meant to specify fn arguments
|
//~| HELP or use `(...)` if you meant to specify fn arguments
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:5:11
|
--> $DIR/require-parens-for-chained-comparison.rs:5:11
|
||||||
|
|
|
|
||||||
LL | false == false == false;
|
LL | false == false == false;
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:8:11
|
--> $DIR/require-parens-for-chained-comparison.rs:8:11
|
||||||
|
|
|
|
||||||
LL | false == 0 < 2;
|
LL | false == 0 < 2;
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:13:6
|
--> $DIR/require-parens-for-chained-comparison.rs:13:6
|
||||||
|
|
|
|
||||||
LL | f<X>();
|
LL | f<X>();
|
||||||
|
@ -21,19 +21,27 @@ help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
LL | f::<X>();
|
LL | f::<X>();
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:17:6
|
--> $DIR/require-parens-for-chained-comparison.rs:17:6
|
||||||
|
|
|
|
||||||
LL | f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
LL | f<Result<Option<X>, Option<Option<X>>>(1, 2);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
|
||||||
|
help: split the comparison into two...
|
||||||
|
|
|
||||||
|
LL | f < Result && Result <Option<X>, Option<Option<X>>>(1, 2);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
help: ...or parenthesize one of the comparisons
|
||||||
|
|
|
||||||
|
LL | (f < Result) <Option<X>, Option<Option<X>>>(1, 2);
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
help: use `::<...>` instead of `<...>` to specify type arguments
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
|
||||||
LL | f::<Result<Option<X>, Option<Option<X>>>(1, 2);
|
LL | f::<Result<Option<X>, Option<Option<X>>>(1, 2);
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: chained comparison operators require parentheses
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/require-parens-for-chained-comparison.rs:22:21
|
--> $DIR/require-parens-for-chained-comparison.rs:24:21
|
||||||
|
|
|
|
||||||
LL | let _ = identity<u8>;
|
LL | let _ = identity<u8>;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Regression test for issue 67856
|
||||||
|
|
||||||
|
#![feature(unboxed_closures)]
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![feature(fn_traits)]
|
||||||
|
|
||||||
|
trait MyTrait {}
|
||||||
|
impl MyTrait for () {}
|
||||||
|
|
||||||
|
impl<F> FnOnce<()> for &F {
|
||||||
|
//~^ ERROR conflicting implementations
|
||||||
|
//~| ERROR type parameter `F` must be used
|
||||||
|
type Output = impl MyTrait;
|
||||||
|
extern "rust-call" fn call_once(self, _: ()) -> Self::Output {}
|
||||||
|
}
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,23 @@
|
||||||
|
error[E0119]: conflicting implementations of trait `std::ops::FnOnce<()>` for type `&_`:
|
||||||
|
--> $DIR/incoherent-assoc-imp-trait.rs:10:1
|
||||||
|
|
|
||||||
|
LL | impl<F> FnOnce<()> for &F {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: conflicting implementation in crate `core`:
|
||||||
|
- impl<A, F> std::ops::FnOnce<A> for &F
|
||||||
|
where F: std::ops::Fn<A>, F: ?Sized;
|
||||||
|
|
||||||
|
error[E0210]: type parameter `F` must be used as the type parameter for some local type (e.g., `MyStruct<F>`)
|
||||||
|
--> $DIR/incoherent-assoc-imp-trait.rs:10:6
|
||||||
|
|
|
||||||
|
LL | impl<F> FnOnce<()> for &F {
|
||||||
|
| ^ type parameter `F` must be used as the type parameter for some local type
|
||||||
|
|
|
||||||
|
= note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
|
||||||
|
= note: only traits defined in the current crate can be implemented for a type parameter
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0119, E0210.
|
||||||
|
For more information about an error, try `rustc --explain E0119`.
|
|
@ -1,4 +1,5 @@
|
||||||
#![crate_name = "compiletest"]
|
#![crate_name = "compiletest"]
|
||||||
|
#![feature(vec_remove_item)]
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
// The `test` crate is the only unstable feature
|
// The `test` crate is the only unstable feature
|
||||||
// allowed here, just to share similar code.
|
// allowed here, just to share similar code.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue