mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 17:03:35 +00:00
Support lint expectations for --force-warn
lints (RFC 2383)
This commit is contained in:
parent
ec55c61305
commit
8527a3d369
@ -340,7 +340,7 @@ fn report_inline_asm(
|
||||
}
|
||||
let level = match level {
|
||||
llvm::DiagnosticLevel::Error => Level::Error { lint: false },
|
||||
llvm::DiagnosticLevel::Warning => Level::Warning,
|
||||
llvm::DiagnosticLevel::Warning => Level::Warning(None),
|
||||
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
|
||||
};
|
||||
cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
|
||||
|
@ -1761,7 +1761,7 @@ impl SharedEmitterMain {
|
||||
|
||||
let mut err = match level {
|
||||
Level::Error { lint: false } => sess.struct_err(msg).forget_guarantee(),
|
||||
Level::Warning => sess.struct_warn(msg),
|
||||
Level::Warning(_) => sess.struct_warn(msg),
|
||||
Level::Note => sess.struct_note_without_error(msg),
|
||||
_ => bug!("Invalid inline asm diagnostic level"),
|
||||
};
|
||||
|
@ -87,7 +87,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType {
|
||||
Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error { .. } => {
|
||||
AnnotationType::Error
|
||||
}
|
||||
Level::Warning => AnnotationType::Warning,
|
||||
Level::Warning(_) => AnnotationType::Warning,
|
||||
Level::Note | Level::OnceNote => AnnotationType::Note,
|
||||
Level::Help => AnnotationType::Help,
|
||||
// FIXME(#59346): Not sure how to map this level
|
||||
|
@ -208,7 +208,7 @@ impl Diagnostic {
|
||||
| Level::Error { .. }
|
||||
| Level::FailureNote => true,
|
||||
|
||||
Level::Warning
|
||||
Level::Warning(_)
|
||||
| Level::Note
|
||||
| Level::OnceNote
|
||||
| Level::Help
|
||||
@ -221,7 +221,9 @@ impl Diagnostic {
|
||||
&mut self,
|
||||
unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
|
||||
) {
|
||||
if let Level::Expect(expectation_id) = &mut self.level {
|
||||
if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) =
|
||||
&mut self.level
|
||||
{
|
||||
if expectation_id.is_stable() {
|
||||
return;
|
||||
}
|
||||
@ -445,7 +447,7 @@ impl Diagnostic {
|
||||
|
||||
/// Add a warning attached to this diagnostic.
|
||||
pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, MultiSpan::new(), None);
|
||||
self.sub(Level::Warning(None), msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
@ -456,7 +458,7 @@ impl Diagnostic {
|
||||
sp: S,
|
||||
msg: impl Into<SubdiagnosticMessage>,
|
||||
) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, sp.into(), None);
|
||||
self.sub(Level::Warning(None), msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ impl Emitter for JsonEmitter {
|
||||
.into_iter()
|
||||
.map(|mut diag| {
|
||||
if diag.level == crate::Level::Allow {
|
||||
diag.level = crate::Level::Warning;
|
||||
diag.level = crate::Level::Warning(None);
|
||||
}
|
||||
FutureBreakageItem { diagnostic: Diagnostic::from_errors_diagnostic(&diag, self) }
|
||||
})
|
||||
|
@ -658,6 +658,23 @@ impl Handler {
|
||||
result
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
|
||||
/// The `id` is used for lint emissions which should also fulfill a lint expectation.
|
||||
///
|
||||
/// Attempting to `.emit()` the builder will only emit if either:
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
pub fn struct_span_warn_with_expectation(
|
||||
&self,
|
||||
span: impl Into<MultiSpan>,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
let mut result = self.struct_warn_with_expectation(msg, id);
|
||||
result.set_span(span);
|
||||
result
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
|
||||
pub fn struct_span_allow(
|
||||
&self,
|
||||
@ -688,7 +705,21 @@ impl Handler {
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Warning, msg)
|
||||
DiagnosticBuilder::new(self, Level::Warning(None), msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Warning` level with the `msg`. The `id` is used for
|
||||
/// lint emissions which should also fulfill a lint expectation.
|
||||
///
|
||||
/// Attempting to `.emit()` the builder will only emit if either:
|
||||
/// * `can_emit_warnings` is `true`
|
||||
/// * `is_force_warn` was set in `DiagnosticId::Lint`
|
||||
pub fn struct_warn_with_expectation(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
DiagnosticBuilder::new(self, Level::Warning(Some(id)), msg)
|
||||
}
|
||||
|
||||
/// Construct a builder at the `Allow` level with the `msg`.
|
||||
@ -842,7 +873,7 @@ impl Handler {
|
||||
}
|
||||
|
||||
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
|
||||
self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
|
||||
self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
|
||||
}
|
||||
|
||||
pub fn span_warn_with_code(
|
||||
@ -851,7 +882,7 @@ impl Handler {
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
code: DiagnosticId,
|
||||
) {
|
||||
self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
|
||||
self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span);
|
||||
}
|
||||
|
||||
pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
|
||||
@ -905,7 +936,7 @@ impl Handler {
|
||||
}
|
||||
|
||||
pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
|
||||
let mut db = DiagnosticBuilder::new(self, Warning, msg);
|
||||
let mut db = DiagnosticBuilder::new(self, Warning(None), msg);
|
||||
db.emit();
|
||||
}
|
||||
|
||||
@ -1010,13 +1041,10 @@ impl Handler {
|
||||
for mut diag in diags.into_iter() {
|
||||
diag.update_unstable_expectation_id(unstable_to_stable);
|
||||
|
||||
let stable_id = diag
|
||||
.level
|
||||
.get_expectation_id()
|
||||
.expect("all diagnostics inside `unstable_expect_diagnostics` must have a `LintExpectationId`");
|
||||
inner.fulfilled_expectations.insert(stable_id);
|
||||
|
||||
(*TRACK_DIAGNOSTICS)(&diag);
|
||||
// Here the diagnostic is given back to `emit_diagnostic` where it was first
|
||||
// intercepted. Now it should be processed as usual, since the unstable expectation
|
||||
// id is now stable.
|
||||
inner.emit_diagnostic(&mut diag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1066,6 +1094,15 @@ impl HandlerInner {
|
||||
|
||||
// FIXME(eddyb) this should ideally take `diagnostic` by value.
|
||||
fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> {
|
||||
// The `LintExpectationId` can be stable or unstable depending on when it was created.
|
||||
// Diagnostics created before the definition of `HirId`s are unstable and can not yet
|
||||
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
|
||||
// a stable one by the `LintLevelsBuilder`.
|
||||
if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() {
|
||||
self.unstable_expect_diagnostics.push(diagnostic.clone());
|
||||
return None;
|
||||
}
|
||||
|
||||
if diagnostic.level == Level::DelayedBug {
|
||||
// FIXME(eddyb) this should check for `has_errors` and stop pushing
|
||||
// once *any* errors were emitted (and truncate `delayed_span_bugs`
|
||||
@ -1082,7 +1119,12 @@ impl HandlerInner {
|
||||
self.future_breakage_diagnostics.push(diagnostic.clone());
|
||||
}
|
||||
|
||||
if diagnostic.level == Warning
|
||||
if let Some(expectation_id) = diagnostic.level.get_expectation_id() {
|
||||
self.suppressed_expected_diag = true;
|
||||
self.fulfilled_expectations.insert(expectation_id);
|
||||
}
|
||||
|
||||
if matches!(diagnostic.level, Warning(_))
|
||||
&& !self.flags.can_emit_warnings
|
||||
&& !diagnostic.is_force_warn()
|
||||
{
|
||||
@ -1092,22 +1134,9 @@ impl HandlerInner {
|
||||
return None;
|
||||
}
|
||||
|
||||
// The `LintExpectationId` can be stable or unstable depending on when it was created.
|
||||
// Diagnostics created before the definition of `HirId`s are unstable and can not yet
|
||||
// be stored. Instead, they are buffered until the `LintExpectationId` is replaced by
|
||||
// a stable one by the `LintLevelsBuilder`.
|
||||
if let Level::Expect(LintExpectationId::Unstable { .. }) = diagnostic.level {
|
||||
self.unstable_expect_diagnostics.push(diagnostic.clone());
|
||||
return None;
|
||||
}
|
||||
|
||||
(*TRACK_DIAGNOSTICS)(diagnostic);
|
||||
|
||||
if let Level::Expect(expectation_id) = diagnostic.level {
|
||||
self.suppressed_expected_diag = true;
|
||||
self.fulfilled_expectations.insert(expectation_id);
|
||||
return None;
|
||||
} else if diagnostic.level == Allow {
|
||||
if matches!(diagnostic.level, Level::Expect(_) | Level::Allow) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -1144,7 +1173,7 @@ impl HandlerInner {
|
||||
self.emitter.emit_diagnostic(&diagnostic);
|
||||
if diagnostic.is_error() {
|
||||
self.deduplicated_err_count += 1;
|
||||
} else if diagnostic.level == Warning {
|
||||
} else if let Warning(_) = diagnostic.level {
|
||||
self.deduplicated_warn_count += 1;
|
||||
}
|
||||
}
|
||||
@ -1197,7 +1226,7 @@ impl HandlerInner {
|
||||
match (errors.len(), warnings.len()) {
|
||||
(0, 0) => return,
|
||||
(0, _) => self.emitter.emit_diagnostic(&Diagnostic::new(
|
||||
Level::Warning,
|
||||
Level::Warning(None),
|
||||
DiagnosticMessage::Str(warnings),
|
||||
)),
|
||||
(_, 0) => {
|
||||
@ -1430,7 +1459,10 @@ pub enum Level {
|
||||
/// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
|
||||
lint: bool,
|
||||
},
|
||||
Warning,
|
||||
/// This [`LintExpectationId`] is used for expected lint diagnostics, which should
|
||||
/// also emit a warning due to the `force-warn` flag. In all other cases this should
|
||||
/// be `None`.
|
||||
Warning(Option<LintExpectationId>),
|
||||
Note,
|
||||
/// A note that is only emitted once.
|
||||
OnceNote,
|
||||
@ -1453,7 +1485,7 @@ impl Level {
|
||||
Bug | DelayedBug | Fatal | Error { .. } => {
|
||||
spec.set_fg(Some(Color::Red)).set_intense(true);
|
||||
}
|
||||
Warning => {
|
||||
Warning(_) => {
|
||||
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
|
||||
}
|
||||
Note | OnceNote => {
|
||||
@ -1472,7 +1504,7 @@ impl Level {
|
||||
match self {
|
||||
Bug | DelayedBug => "error: internal compiler error",
|
||||
Fatal | Error { .. } => "error",
|
||||
Warning => "warning",
|
||||
Warning(_) => "warning",
|
||||
Note | OnceNote => "note",
|
||||
Help => "help",
|
||||
FailureNote => "failure-note",
|
||||
@ -1487,7 +1519,7 @@ impl Level {
|
||||
|
||||
pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
|
||||
match self {
|
||||
Level::Expect(id) => Some(*id),
|
||||
Level::Expect(id) | Level::Warning(Some(id)) => Some(*id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ impl ToInternal<rustc_errors::Level> for Level {
|
||||
fn to_internal(self) -> rustc_errors::Level {
|
||||
match self {
|
||||
Level::Error => rustc_errors::Level::Error { lint: false },
|
||||
Level::Warning => rustc_errors::Level::Warning,
|
||||
Level::Warning => rustc_errors::Level::Warning(None),
|
||||
Level::Note => rustc_errors::Level::Note,
|
||||
Level::Help => rustc_errors::Level::Help,
|
||||
_ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
|
||||
|
@ -324,7 +324,7 @@ impl LintStore {
|
||||
registered_tools: &RegisteredTools,
|
||||
) {
|
||||
let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
|
||||
if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn {
|
||||
if lint_name_only == crate::WARNINGS.name_lower() && matches!(level, Level::ForceWarn(_)) {
|
||||
struct_span_err!(
|
||||
sess,
|
||||
DUMMY_SP,
|
||||
@ -375,7 +375,7 @@ impl LintStore {
|
||||
match level {
|
||||
Level::Allow => "-A",
|
||||
Level::Warn => "-W",
|
||||
Level::ForceWarn => "--force-warn",
|
||||
Level::ForceWarn(_) => "--force-warn",
|
||||
Level::Deny => "-D",
|
||||
Level::Forbid => "-F",
|
||||
Level::Expect(_) => {
|
||||
|
@ -19,16 +19,16 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
|
||||
let lint_expectations = &tcx.lint_levels(()).lint_expectations;
|
||||
|
||||
for (id, expectation) in lint_expectations {
|
||||
if !fulfilled_expectations.contains(id)
|
||||
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
|
||||
{
|
||||
// This check will always be true, since `lint_expectations` only
|
||||
// holds stable ids
|
||||
if let LintExpectationId::Stable { hir_id, .. } = id {
|
||||
// This check will always be true, since `lint_expectations` only
|
||||
// holds stable ids
|
||||
if let LintExpectationId::Stable { hir_id, .. } = id {
|
||||
if !fulfilled_expectations.contains(&id)
|
||||
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
|
||||
{
|
||||
emit_unfulfilled_expectation_lint(tcx, *hir_id, expectation);
|
||||
} else {
|
||||
unreachable!("at this stage all `LintExpectationId`s are stable");
|
||||
}
|
||||
} else {
|
||||
unreachable!("at this stage all `LintExpectationId`s are stable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,9 @@ impl<'s> LintLevelsBuilder<'s> {
|
||||
};
|
||||
for id in ids {
|
||||
// ForceWarn and Forbid cannot be overridden
|
||||
if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
|
||||
if let Some((Level::ForceWarn(_) | Level::Forbid, _)) =
|
||||
self.current_specs().get(&id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -226,11 +228,18 @@ impl<'s> LintLevelsBuilder<'s> {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Level::ForceWarn = old_level {
|
||||
self.current_specs_mut().insert(id, (old_level, old_src));
|
||||
} else {
|
||||
self.current_specs_mut().insert(id, (level, src));
|
||||
}
|
||||
match (old_level, level) {
|
||||
// If the new level is an expectation store it in `ForceWarn`
|
||||
(Level::ForceWarn(_), Level::Expect(expectation_id)) => self
|
||||
.current_specs_mut()
|
||||
.insert(id, (Level::ForceWarn(Some(expectation_id)), old_src)),
|
||||
// Keep `ForceWarn` level but drop the expectation
|
||||
(Level::ForceWarn(_), _) => {
|
||||
self.current_specs_mut().insert(id, (Level::ForceWarn(None), old_src))
|
||||
}
|
||||
// Set the lint level as normal
|
||||
_ => self.current_specs_mut().insert(id, (level, src)),
|
||||
};
|
||||
}
|
||||
|
||||
/// Pushes a list of AST lint attributes onto this context.
|
||||
@ -269,6 +278,7 @@ impl<'s> LintLevelsBuilder<'s> {
|
||||
|
||||
let level = match Level::from_attr(attr) {
|
||||
None => continue,
|
||||
// This is the only lint level with a `LintExpectationId` that can be created from an attribute
|
||||
Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => {
|
||||
let stable_id = self.create_stable_id(unstable_id, hir_id, attr_index);
|
||||
|
||||
|
@ -162,13 +162,19 @@ pub enum Level {
|
||||
///
|
||||
/// See RFC 2383.
|
||||
///
|
||||
/// The `LintExpectationId` is used to later link a lint emission to the actual
|
||||
/// The [`LintExpectationId`] is used to later link a lint emission to the actual
|
||||
/// expectation. It can be ignored in most cases.
|
||||
Expect(LintExpectationId),
|
||||
/// The `warn` level will produce a warning if the lint was violated, however the
|
||||
/// compiler will continue with its execution.
|
||||
Warn,
|
||||
ForceWarn,
|
||||
/// This lint level is a special case of [`Warn`], that can't be overridden. This is used
|
||||
/// to ensure that a lint can't be suppressed. This lint level can currently only be set
|
||||
/// via the console and is therefore session specific.
|
||||
///
|
||||
/// The [`LintExpectationId`] is intended to fulfill expectations marked via the
|
||||
/// `#[expect]` attribute, that will still be suppressed due to the level.
|
||||
ForceWarn(Option<LintExpectationId>),
|
||||
/// The `deny` level will produce an error and stop further execution after the lint
|
||||
/// pass is complete.
|
||||
Deny,
|
||||
@ -184,7 +190,7 @@ impl Level {
|
||||
Level::Allow => "allow",
|
||||
Level::Expect(_) => "expect",
|
||||
Level::Warn => "warn",
|
||||
Level::ForceWarn => "force-warn",
|
||||
Level::ForceWarn(_) => "force-warn",
|
||||
Level::Deny => "deny",
|
||||
Level::Forbid => "forbid",
|
||||
}
|
||||
@ -219,7 +225,7 @@ impl Level {
|
||||
|
||||
pub fn is_error(self) -> bool {
|
||||
match self {
|
||||
Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn => false,
|
||||
Level::Allow | Level::Expect(_) | Level::Warn | Level::ForceWarn(_) => false,
|
||||
Level::Deny | Level::Forbid => true,
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ impl LintLevelSets {
|
||||
|
||||
// Ensure that we never exceed the `--cap-lints` argument
|
||||
// unless the source is a --force-warn
|
||||
level = if let LintLevelSource::CommandLine(_, Level::ForceWarn) = src {
|
||||
level = if let LintLevelSource::CommandLine(_, Level::ForceWarn(_)) = src {
|
||||
level
|
||||
} else {
|
||||
cmp::min(level, self.lint_cap)
|
||||
@ -266,7 +266,7 @@ pub fn explain_lint_level_source(
|
||||
Level::Deny => "-D",
|
||||
Level::Forbid => "-F",
|
||||
Level::Allow => "-A",
|
||||
Level::ForceWarn => "--force-warn",
|
||||
Level::ForceWarn(_) => "--force-warn",
|
||||
Level::Expect(_) => {
|
||||
unreachable!("the expect level does not have a commandline flag")
|
||||
}
|
||||
@ -352,8 +352,14 @@ pub fn struct_lint_level<'s, 'd>(
|
||||
// create a `DiagnosticBuilder` and continue as we would for warnings.
|
||||
sess.struct_expect("", expect_id)
|
||||
}
|
||||
(Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""),
|
||||
(Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""),
|
||||
(Level::ForceWarn(Some(expect_id)), Some(span)) => {
|
||||
sess.struct_span_warn_with_expectation(span, "", expect_id)
|
||||
}
|
||||
(Level::ForceWarn(Some(expect_id)), None) => {
|
||||
sess.struct_warn_with_expectation("", expect_id)
|
||||
}
|
||||
(Level::Warn | Level::ForceWarn(None), Some(span)) => sess.struct_span_warn(span, ""),
|
||||
(Level::Warn | Level::ForceWarn(None), None) => sess.struct_warn(""),
|
||||
(Level::Deny | Level::Forbid, Some(span)) => {
|
||||
let mut builder = sess.diagnostic().struct_err_lint("");
|
||||
builder.set_span(span);
|
||||
@ -398,7 +404,7 @@ pub fn struct_lint_level<'s, 'd>(
|
||||
explain_lint_level_source(lint, level, src, &mut err);
|
||||
|
||||
let name = lint.name_lower();
|
||||
let is_force_warn = matches!(level, Level::ForceWarn);
|
||||
let is_force_warn = matches!(level, Level::ForceWarn(_));
|
||||
err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
|
||||
|
||||
if let Some(future_incompatible) = future_incompatible {
|
||||
|
@ -1432,7 +1432,7 @@ pub fn get_cmd_lint_options(
|
||||
let mut lint_opts_with_position = vec![];
|
||||
let mut describe_lints = false;
|
||||
|
||||
for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
|
||||
for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
|
||||
for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
|
||||
if lint_name == "help" {
|
||||
describe_lints = true;
|
||||
|
@ -286,6 +286,14 @@ impl Session {
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
self.diagnostic().struct_span_warn(sp, msg)
|
||||
}
|
||||
pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: lint::LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
|
||||
}
|
||||
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
@ -297,6 +305,13 @@ impl Session {
|
||||
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
|
||||
self.diagnostic().struct_warn(msg)
|
||||
}
|
||||
pub fn struct_warn_with_expectation(
|
||||
&self,
|
||||
msg: impl Into<DiagnosticMessage>,
|
||||
id: lint::LintExpectationId,
|
||||
) -> DiagnosticBuilder<'_, ()> {
|
||||
self.diagnostic().struct_warn_with_expectation(msg, id)
|
||||
}
|
||||
pub fn struct_span_allow<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
|
@ -0,0 +1,48 @@
|
||||
// compile-flags: --force-warn while_true
|
||||
// compile-flags: --force-warn unused_variables
|
||||
// compile-flags: --force-warn unused_mut
|
||||
// check-pass
|
||||
|
||||
#![feature(lint_reasons)]
|
||||
|
||||
fn expect_early_pass_lint() {
|
||||
#[expect(while_true)]
|
||||
while true {
|
||||
//~^ WARNING denote infinite loops with `loop { ... }` [while_true]
|
||||
//~| NOTE requested on the command line with `--force-warn while-true`
|
||||
//~| HELP use `loop`
|
||||
println!("I never stop")
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(unused_variables, reason="<this should fail and display this reason>")]
|
||||
fn check_specific_lint() {
|
||||
let x = 2;
|
||||
//~^ WARNING unused variable: `x` [unused_variables]
|
||||
//~| NOTE requested on the command line with `--force-warn unused-variables`
|
||||
//~| HELP if this is intentional, prefix it with an underscore
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
fn check_multiple_lints_with_lint_group() {
|
||||
let fox_name = "Sir Nibbles";
|
||||
//~^ WARNING unused variable: `fox_name` [unused_variables]
|
||||
//~| HELP if this is intentional, prefix it with an underscore
|
||||
|
||||
let mut what_does_the_fox_say = "*ding* *deng* *dung*";
|
||||
//~^ WARNING variable does not need to be mutable [unused_mut]
|
||||
//~| NOTE requested on the command line with `--force-warn unused-mut`
|
||||
//~| HELP remove this `mut`
|
||||
|
||||
println!("The fox says: {what_does_the_fox_say}");
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn check_expect_overrides_allow_lint_level() {
|
||||
#[expect(unused_variables)]
|
||||
let this_should_fulfill_the_expectation = "The `#[allow]` has no power here";
|
||||
//~^ WARNING unused variable: `this_should_fulfill_the_expectation` [unused_variables]
|
||||
//~| HELP if this is intentional, prefix it with an underscore
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,40 @@
|
||||
warning: denote infinite loops with `loop { ... }`
|
||||
--> $DIR/force_warn_expected_lints_fulfilled.rs:10:5
|
||||
|
|
||||
LL | while true {
|
||||
| ^^^^^^^^^^ help: use `loop`
|
||||
|
|
||||
= note: requested on the command line with `--force-warn while-true`
|
||||
|
||||
warning: unused variable: `x`
|
||||
--> $DIR/force_warn_expected_lints_fulfilled.rs:20:9
|
||||
|
|
||||
LL | let x = 2;
|
||||
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
||||
|
|
||||
= note: requested on the command line with `--force-warn unused-variables`
|
||||
|
||||
warning: unused variable: `fox_name`
|
||||
--> $DIR/force_warn_expected_lints_fulfilled.rs:28:9
|
||||
|
|
||||
LL | let fox_name = "Sir Nibbles";
|
||||
| ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_fox_name`
|
||||
|
||||
warning: unused variable: `this_should_fulfill_the_expectation`
|
||||
--> $DIR/force_warn_expected_lints_fulfilled.rs:43:9
|
||||
|
|
||||
LL | let this_should_fulfill_the_expectation = "The `#[allow]` has no power here";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_fulfill_the_expectation`
|
||||
|
||||
warning: variable does not need to be mutable
|
||||
--> $DIR/force_warn_expected_lints_fulfilled.rs:32:9
|
||||
|
|
||||
LL | let mut what_does_the_fox_say = "*ding* *deng* *dung*";
|
||||
| ----^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| help: remove this `mut`
|
||||
|
|
||||
= note: requested on the command line with `--force-warn unused-mut`
|
||||
|
||||
warning: 5 warnings emitted
|
||||
|
@ -0,0 +1,49 @@
|
||||
// compile-flags: --force-warn while_true
|
||||
// compile-flags: --force-warn unused_variables
|
||||
// compile-flags: --force-warn unused_mut
|
||||
// check-pass
|
||||
|
||||
#![feature(lint_reasons)]
|
||||
|
||||
fn expect_early_pass_lint(terminate: bool) {
|
||||
#[expect(while_true)]
|
||||
//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
|
||||
//~| NOTE `#[warn(unfulfilled_lint_expectations)]` on by default
|
||||
while !terminate {
|
||||
println!("Do you know what a spin lock is?")
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(unused_variables, reason="<this should fail and display this reason>")]
|
||||
//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
|
||||
//~| NOTE <this should fail and display this reason>
|
||||
fn check_specific_lint() {
|
||||
let _x = 2;
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
|
||||
fn check_multiple_lints_with_lint_group() {
|
||||
let fox_name = "Sir Nibbles";
|
||||
|
||||
let what_does_the_fox_say = "*ding* *deng* *dung*";
|
||||
|
||||
println!("The fox says: {what_does_the_fox_say}");
|
||||
println!("~ {fox_name}")
|
||||
}
|
||||
|
||||
|
||||
#[expect(unused)]
|
||||
//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
|
||||
fn check_overridden_expectation_lint_level() {
|
||||
#[allow(unused_variables)]
|
||||
let this_should_not_fulfill_the_expectation = "maybe";
|
||||
//~^ WARNING unused variable: `this_should_not_fulfill_the_expectation` [unused_variables]
|
||||
//~| NOTE requested on the command line with `--force-warn unused-variables`
|
||||
//~| HELP if this is intentional, prefix it with an underscore
|
||||
}
|
||||
|
||||
fn main() {
|
||||
check_multiple_lints_with_lint_group();
|
||||
check_overridden_expectation_lint_level();
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
warning: unused variable: `this_should_not_fulfill_the_expectation`
|
||||
--> $DIR/force_warn_expected_lints_unfulfilled.rs:40:9
|
||||
|
|
||||
LL | let this_should_not_fulfill_the_expectation = "maybe";
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_this_should_not_fulfill_the_expectation`
|
||||
|
|
||||
= note: requested on the command line with `--force-warn unused-variables`
|
||||
|
||||
warning: this lint expectation is unfulfilled
|
||||
--> $DIR/force_warn_expected_lints_unfulfilled.rs:9:14
|
||||
|
|
||||
LL | #[expect(while_true)]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
|
||||
|
||||
warning: this lint expectation is unfulfilled
|
||||
--> $DIR/force_warn_expected_lints_unfulfilled.rs:17:10
|
||||
|
|
||||
LL | #[expect(unused_variables, reason="<this should fail and display this reason>")]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: <this should fail and display this reason>
|
||||
|
||||
warning: this lint expectation is unfulfilled
|
||||
--> $DIR/force_warn_expected_lints_unfulfilled.rs:24:10
|
||||
|
|
||||
LL | #[expect(unused)]
|
||||
| ^^^^^^
|
||||
|
||||
warning: this lint expectation is unfulfilled
|
||||
--> $DIR/force_warn_expected_lints_unfulfilled.rs:36:10
|
||||
|
|
||||
LL | #[expect(unused)]
|
||||
| ^^^^^^
|
||||
|
||||
warning: 5 warnings emitted
|
||||
|
@ -433,7 +433,7 @@ mod tests {
|
||||
Some(ignore_list),
|
||||
);
|
||||
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
||||
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
|
||||
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
|
||||
emitter.emit_diagnostic(&non_fatal_diagnostic);
|
||||
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
|
||||
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
|
||||
@ -457,7 +457,7 @@ mod tests {
|
||||
None,
|
||||
);
|
||||
let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
||||
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
|
||||
let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
|
||||
emitter.emit_diagnostic(&non_fatal_diagnostic);
|
||||
assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
|
||||
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
|
||||
@ -494,8 +494,8 @@ mod tests {
|
||||
);
|
||||
let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
|
||||
let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22)));
|
||||
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
|
||||
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
|
||||
let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(bar_span));
|
||||
let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(foo_span));
|
||||
let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
|
||||
emitter.emit_diagnostic(&bar_diagnostic);
|
||||
emitter.emit_diagnostic(&foo_diagnostic);
|
||||
|
Loading…
Reference in New Issue
Block a user