From 47da3f0b9576df2b5c0b5a4d3abf08716fc07a88 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 23 Jan 2020 19:02:55 -0500 Subject: [PATCH 1/6] Maybe working --- src/librustc/lint.rs | 187 +++++++++++++++++---------- src/librustc_lint/builtin.rs | 2 +- src/librustc_lint/levels.rs | 49 ++++++- src/librustc_session/lint.rs | 46 +++++++ src/librustc_session/lint/builtin.rs | 31 ++--- 5 files changed, 225 insertions(+), 90 deletions(-) diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs index 2ed6cd5283b10..f0a7eb96c5dd3 100644 --- a/src/librustc/lint.rs +++ b/src/librustc/lint.rs @@ -19,10 +19,10 @@ pub enum LintSource { Default, /// Lint level was set by an attribute. - Node(Symbol, Span, Option /* RFC 2383 reason */), + Node(Symbol, Option, Span, Option /* RFC 2383 reason */), /// Lint level was set by a command-line flag. - CommandLine(Symbol), + CommandLine(Symbol, Option), } pub type LevelSource = (Level, LintSource); @@ -63,16 +63,26 @@ impl LintLevelSets { // lint. let mut level = level.unwrap_or_else(|| lint.default_level(sess.edition())); + // Ensure we don't go below the minimum level of the lint. + // Note that we allow `--cap-lints` to cap `WARNINGS`, + // but we will never allow `--cap-lints` to cap the lint itself. + let warn_level = cmp::max(level, lint.min_level); + // 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 { + if warn_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 { + let orig_level = Some(level); level = configured_warning_level; - src = warnings_src; + src = match warnings_src { + LintSource::CommandLine(s, _) => LintSource::CommandLine(s, orig_level), + LintSource::Node(n, _, s, r) => LintSource::Node(n, orig_level, s, r), + other => other, + }; } } } @@ -174,6 +184,10 @@ impl<'a> HashStable> for LintLevelMap { } } +fn hyphenate(s: &str) -> String { + s.replace("_", "-") +} + pub fn struct_lint_level<'a>( sess: &'a Session, lint: &'static Lint, @@ -182,6 +196,13 @@ pub fn struct_lint_level<'a>( span: Option, msg: &str, ) -> DiagnosticBuilder<'a> { + // Pick the highest level of the given one and the minimum. + // The effect of this is that if e.g. `min_level == Warn` and + // you have `#[allow({lint.name})]` then a warning will still + // be emitted. + let min_level = lint.min_level; + let level = cmp::max(orig_level, min_level); + let mut err = match (level, span) { (Level::Allow, _) => return sess.diagnostic().struct_dummy(), (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg), @@ -214,92 +235,118 @@ pub fn struct_lint_level<'a>( } let name = lint.name_lower(); - match src { + let diag_msg_id = DiagnosticMessageId::from(lint); + let pre_warn_level = match src { LintSource::Default => { - sess.diag_note_once( - &mut err, - DiagnosticMessageId::from(lint), - &format!("`#[{}({})]` on by default", level.as_str(), name), - ); + let msg = &format!("#[{}({})] on by default", orig_level.as_str(), name); + sess.diag_note_once(&mut err, diag_msg_id, msg); + None } 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 - ), - ); + let flag = orig_level.level_to_flag(); + let lint_name = hyphenate(&name); + let msg = if lint_flag_val.as_str() == name { + format!("requested on the command line with `{} {}`", flag, 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 - ), - ); - } + let flag_val = hyphenate(&lint_flag_val.as_str()); + format!("`{} {}` implied by `{} {}`", flag, lint_name, flag, flag_val) + }; + sess.diag_note_once(&mut err, diag_msg_id, &msg); + pre_warn_level } LintSource::Node(lint_attr_name, src, reason) => { - if let Some(rationale) = reason { - err.note(&rationale.as_str()); + if orig_level >= level || pre_warn_level.is_some() { + 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", - ); + + sess.diag_span_note_once(&mut err, diag_msg_id, 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 - ), + let level_str = orig_level.as_str(); + let msg = format!( + "#[{}({})] implied by #[{}({})]", + level_str, name, level_str, lint_attr_name ); + sess.diag_note_once(&mut err, diag_msg_id, &msg); } + + pre_warn_level } + }; + + // Highlight the minimum as cause of the lint iff it was raised due to the minimum. + let orig_level = pre_warn_level.map(|pwl| cmp::min(pwl, orig_level)).unwrap_or(orig_level); + if orig_level < min_level { + let min_msg = format!("#[{}({})] is the minimum lint level", min_level.as_str(), name); + let rem_msg = format!("the lint level cannot be reduced to `{}`", orig_level.as_str()); + sess.diag_note_once(&mut err, diag_msg_id, &min_msg); + sess.diag_note_once(&mut err, diag_msg_id, &rem_msg) } 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"; + check_future_compatibility(sess, lint, &mut err, Option::<&str>::None); + + return err; +} - 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() +/// Check for future incompatibility lints and issue a stronger warning. +pub fn check_future_compatibility<'a>( + sess: &'a Session, + lint: &'static Lint, + err: &mut DiagnosticBuilder<'_>, + name: Option, +) { + // Check for future incompatibility lints and issue a stronger warning. + let lints = sess.lint_store.borrow(); + let lint_id = LintId::of(lint); + let future_incompatible = lints.future_incompatible(lint_id); + if let Some(future_incompatible) = future_incompatible { + if lint_id == LintId::of(crate::lint::builtin::UNSTABLE_NAME_COLLISIONS) { + err.warn( + "once this method is added to the standard library, \ + the ambiguity may cause an error or change in behavior!", + ); } 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) + err.warn( + "this borrowing pattern was not meant to be accepted, \ + and may become a hard error in the future", + ); } else { - format!("{} in a future release!", STANDARD_MESSAGE) - }; - let citation = format!("for more information, see {}", future_incompatible.reference); - err.warn(&explanation); - err.note(&citation); + let previously_msg = if let Some(n) = name { + format!("`{}` was previously accepted by the compiler but is being phased out", n) + } else { + format!("this was previously accepted by the compiler but is being phased out") + }; + err.warn(&previously_msg); + + let hard_err_msg = if let Some(edition) = future_incompatible.edition { + format!("it will become a hard error in the {} edition!", edition) + } else { + format!("it will become a hard error in a future release!") + }; + err.warn(&hard_err_msg); + } + + err.note(&format!("for more information, see {}", future_incompatible.reference)); } - return err; + // 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() + } + } } /// Returns whether `span` originates in a foreign crate's external macro. diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c8d3d5f9c83d8..1c6e5e3c07c62 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1050,7 +1050,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { } } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index d5bbdc53160f6..294b08f89fb3d 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -85,7 +85,7 @@ impl<'a> LintLevelsBuilder<'a> { Err(_) => continue, // errors handled in check_lint_name_cmdline above }; for id in ids { - let src = LintSource::CommandLine(lint_flag_val); + let src = LintSource::CommandLine(lint_flag_val, None); specs.insert(id, (level, src)); } } @@ -211,7 +211,7 @@ impl<'a> LintLevelsBuilder<'a> { 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); + let src = LintSource::Node(name, None, li.span(), reason); for id in ids { specs.insert(*id, (level, src)); } @@ -223,6 +223,7 @@ impl<'a> LintLevelsBuilder<'a> { let complete_name = &format!("{}::{}", tool_name.unwrap(), name); let src = LintSource::Node( Symbol::intern(complete_name), + None, li.span(), reason, ); @@ -258,6 +259,7 @@ impl<'a> LintLevelsBuilder<'a> { let src = LintSource::Node( Symbol::intern(&new_lint_name), + None, li.span(), reason, ); @@ -328,6 +330,8 @@ impl<'a> LintLevelsBuilder<'a> { } for (id, &(level, ref src)) in specs.iter() { + self.lint_higher_minimum_attr_lint(id.lint, level, src, &specs); + if level == Level::Forbid { continue; } @@ -337,8 +341,8 @@ impl<'a> LintLevelsBuilder<'a> { }; let forbidden_lint_name = match forbid_src { LintSource::Default => id.to_string(), - LintSource::Node(name, _, _) => name.to_string(), - LintSource::CommandLine(name) => name.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), @@ -380,6 +384,43 @@ impl<'a> LintLevelsBuilder<'a> { BuilderPush { prev: prev, changed: prev != self.cur } } + /// If we have e.g. `#[allow($some_future_compat_lint)]` this will have + /// no effect as `min_level > Allow`. We want to tell the user about this. + fn lint_higher_minimum_attr_lint( + &self, + lint: &'static Lint, + level: Level, + src: &LintSource, + specs: &FxHashMap, + ) { + let min_level = lint.min_level; + if min_level <= level { + return; + } + + if let LintSource::Node(name, _, span, _) = src { + // Get the `unused_attributes` lint specs: + let unused = builtin::UNUSED_ATTRIBUTES; + let (lvl, src) = self.sets.get_lint_level(unused, self.cur, Some(&specs), &self.sess); + + // Construct base diagnostic for `unused_attributes`: + let level_str = level.as_str(); + let msg = format!("#[{}({})] has no effect", level_str, name); + let multi_span = Some((*span).into()); + let mut err = lint::struct_lint_level(self.sess, unused, lvl, src, multi_span, &msg); + + // Add notes about minimum levels and what the user should do here: + err.note(&format!("the minimum lint level for `{}` is `{}`", name, min_level.as_str())) + .note(&format!("the lint level cannot be reduced to `{}`", level_str)) + .help(&format!("remove the #[{}({})] directive", level_str, name)); + + // If it is a future compat lint, warn the user about it. + crate::lint::check_future_compatibility(self.sess, lint, &mut err, Some(name)); + + err.emit(); + } + } + /// Called after `push` when the scope of a set of attributes are exited. pub fn pop(&mut self, push: BuilderPush) { self.cur = push.prev; diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index 2ba3932c7d97e..2e45e2f2312d6 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -49,6 +49,15 @@ impl Level { _ => None, } } + + fn level_to_flag(self) -> &'static str { + match self { + Level::Warn => "-W", + Level::Deny => "-D", + Level::Forbid => "-F", + Level::Allow => "-A", + } + } } /// Specification of a single lint. @@ -69,6 +78,11 @@ pub struct Lint { /// Default level for the lint. pub default_level: Level, + /// The minimum level this lint can be loosened to. + /// For example, suppose we have `#[allow(my_lint)]` and `min_level == Warn`. + /// In that case, a warning will still be emitted. + pub min_level: Level, + /// Description of the lint or the issue it detects. /// /// e.g., "imports that are never used" @@ -277,6 +291,7 @@ macro_rules! declare_lint { $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, + min_level: $crate::lint::Allow, desc: $desc, edition_lint_opts: None, is_plugin: false, @@ -291,6 +306,7 @@ macro_rules! declare_lint { $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, + min_level: $crate::lint::Allow, desc: $desc, edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)), report_in_external_macro: false, @@ -299,6 +315,35 @@ macro_rules! declare_lint { ); } +/// Declares a static item of type `&'static Lint` that is unsuppressable. +/// +/// This means that the lint will have `Warn` as the minimum lint level. +/// Therefore, it cannot be `#[allow(..)]`ed. +/// +/// This lint should be used for C-future-compatibility lints on an opt-in +/// case-by-case basis. +/// +/// Note that the default is to use `declare_lint!`. It is recommended that +/// a lint spend at least one release cycle using `declare_lint!` before +/// moving to `declare_unsuppressable_lint!`. +/// +/// Before moving the C-future-compatibility lint into a hard error, +/// it is also recommended that `declare_unsuppressable_lint!` be used +/// at least one release cycle. +#[macro_export] +macro_rules! declare_unsuppressable_lint { + ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => { + $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { + name: stringify!($NAME), + default_level: $crate::lint::$Level, + min_level: $crate::lint::Warn, + desc: $desc, + edition_lint_opts: None, + report_in_external_macro: false, + }; + }; +} + #[macro_export] macro_rules! declare_tool_lint { ( @@ -320,6 +365,7 @@ macro_rules! declare_tool_lint { $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: &concat!(stringify!($tool), "::", stringify!($NAME)), default_level: $crate::lint::$Level, + min_level: $crate::lint::Allow, desc: $desc, edition_lint_opts: None, report_in_external_macro: $external, diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 3e8503ef661f0..ff5da9a3e6705 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -8,7 +8,7 @@ use crate::lint::FutureIncompatibleInfo; use crate::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub ILL_FORMED_ATTRIBUTE_INPUT, Deny, "ill-formed attribute inputs that were previously accepted and used in practice", @@ -78,14 +78,15 @@ declare_lint! { Warn, "detect assignments that will never be read" } +hings have progressed, + // consider using `declare_unsuppressable_lint!` instead. -declare_lint! { - pub DEAD_CODE, +declare_lint! {his will t Warn, "detect unused, unexported items" } -declare_lint! { +declare_lint! { k// - By default, `udeclare_linbt!` is recommended for use to declare the pub UNUSED_ATTRIBUTES, Warn, "detects attributes that were not used by the compiler" @@ -158,7 +159,7 @@ declare_lint! { "detects trivial casts of numeric types which could be removed" } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub PRIVATE_IN_PUBLIC, Warn, "detect private items in public interfaces not caught by the old implementation", @@ -184,7 +185,7 @@ declare_lint! { }; } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub INVALID_TYPE_PARAM_DEFAULT, Deny, "type parameter default erroneously allowed in invalid location", @@ -200,7 +201,7 @@ declare_lint! { "lints that have been renamed or removed" } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub SAFE_PACKED_BORROWS, Warn, "safe borrows of fields of packed structs were was erroneously allowed", @@ -210,7 +211,7 @@ declare_lint! { }; } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub PATTERNS_IN_FNS_WITHOUT_BODY, Deny, "patterns in functions without body were erroneously allowed", @@ -220,7 +221,7 @@ declare_lint! { }; } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub MISSING_FRAGMENT_SPECIFIER, Deny, "detects missing fragment specifiers in unused `macro_rules!` patterns", @@ -230,7 +231,7 @@ declare_lint! { }; } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub LATE_BOUND_LIFETIME_ARGUMENTS, Warn, "detects generic lifetime arguments in path segments with late bound lifetime parameters", @@ -240,7 +241,7 @@ declare_lint! { }; } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub ORDER_DEPENDENT_TRAIT_OBJECTS, Deny, "trait-object types were treated as different depending on marker-trait order", @@ -287,7 +288,7 @@ declare_lint! { "detects lifetime parameters that are never used" } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub TYVAR_BEHIND_RAW_POINTER, Warn, "raw pointer to an inference variable", @@ -320,7 +321,7 @@ declare_lint! { }; } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, Warn, "floating-point literals cannot be used in patterns", @@ -372,7 +373,7 @@ declare_lint! { "detects code samples in docs of private items not documented by rustdoc" } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub WHERE_CLAUSES_OBJECT_SAFETY, Warn, "checks the object safety of where clauses", @@ -434,7 +435,7 @@ declare_lint! { report_in_external_macro } -declare_lint! { +declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` pub AMBIGUOUS_ASSOCIATED_ITEMS, Deny, "ambiguous associated items", From bc1b37d7a46201fb1451b27a50026fd8045fccbc Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 23 Jan 2020 19:04:44 -0500 Subject: [PATCH 2/6] Fix garbage --- src/librustc_session/lint/builtin.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index ff5da9a3e6705..6612558f32cbc 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -78,15 +78,13 @@ declare_lint! { Warn, "detect assignments that will never be read" } -hings have progressed, - // consider using `declare_unsuppressable_lint!` instead. -declare_lint! {his will t +declare_lint! { Warn, "detect unused, unexported items" } -declare_lint! { k// - By default, `udeclare_linbt!` is recommended for use to declare the +declare_lint! { pub UNUSED_ATTRIBUTES, Warn, "detects attributes that were not used by the compiler" From d3e5b4087b9952695298d5b5e92ed57c095b8028 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 23 Jan 2020 19:16:42 -0500 Subject: [PATCH 3/6] Get it compiling --- src/librustc/lint.rs | 11 +++++------ src/librustc_lint/levels.rs | 12 ++++++------ src/librustc_session/lint.rs | 3 ++- src/librustc_session/lint/builtin.rs | 1 + 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs index f0a7eb96c5dd3..dbb0152b2a993 100644 --- a/src/librustc/lint.rs +++ b/src/librustc/lint.rs @@ -191,7 +191,7 @@ fn hyphenate(s: &str) -> String { pub fn struct_lint_level<'a>( sess: &'a Session, lint: &'static Lint, - level: Level, + orig_level: Level, src: LintSource, span: Option, msg: &str, @@ -242,7 +242,7 @@ pub fn struct_lint_level<'a>( sess.diag_note_once(&mut err, diag_msg_id, msg); None } - LintSource::CommandLine(lint_flag_val) => { + LintSource::CommandLine(lint_flag_val, pre_warn_level) => { let flag = orig_level.level_to_flag(); let lint_name = hyphenate(&name); let msg = if lint_flag_val.as_str() == name { @@ -254,7 +254,7 @@ pub fn struct_lint_level<'a>( sess.diag_note_once(&mut err, diag_msg_id, &msg); pre_warn_level } - LintSource::Node(lint_attr_name, src, reason) => { + LintSource::Node(lint_attr_name, pre_warn_level, src, reason) => { if orig_level >= level || pre_warn_level.is_some() { if let Some(rationale) = reason { err.note(&rationale.as_str()); @@ -296,12 +296,11 @@ pub fn check_future_compatibility<'a>( sess: &'a Session, lint: &'static Lint, err: &mut DiagnosticBuilder<'_>, - name: Option, + name: Option, ) { // Check for future incompatibility lints and issue a stronger warning. - let lints = sess.lint_store.borrow(); let lint_id = LintId::of(lint); - let future_incompatible = lints.future_incompatible(lint_id); + let future_incompatible = lint.future_incompatible; if let Some(future_incompatible) = future_incompatible { if lint_id == LintId::of(crate::lint::builtin::UNSTABLE_NAME_COLLISIONS) { err.warn( diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 294b08f89fb3d..5c862e6075b83 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -11,7 +11,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::hir_id::HirId; use rustc_hir::intravisit; -use rustc_session::lint::{builtin, Level, Lint}; +use rustc_session::lint::{builtin, Level, Lint, LintId}; use rustc_session::Session; use rustc_span::{sym, MultiSpan, Symbol}; use syntax::ast; @@ -345,7 +345,7 @@ impl<'a> LintLevelsBuilder<'a> { LintSource::CommandLine(name, _) => name.to_string(), }; let (lint_attr_name, lint_attr_span) = match *src { - LintSource::Node(name, span, _) => (name, span), + LintSource::Node(name, _, span, _) => (name, span), _ => continue, }; let mut diag_builder = struct_span_err!( @@ -360,13 +360,13 @@ impl<'a> LintLevelsBuilder<'a> { diag_builder.span_label(lint_attr_span, "overruled by previous forbid"); match forbid_src { LintSource::Default => {} - LintSource::Node(_, forbid_source_span, reason) => { + 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(_) => { + LintSource::CommandLine(_, _) => { diag_builder.note("`forbid` lint level was set on command line"); } } @@ -407,7 +407,7 @@ impl<'a> LintLevelsBuilder<'a> { let level_str = level.as_str(); let msg = format!("#[{}({})] has no effect", level_str, name); let multi_span = Some((*span).into()); - let mut err = lint::struct_lint_level(self.sess, unused, lvl, src, multi_span, &msg); + let mut err = struct_lint_level(self.sess, unused, lvl, src, multi_span, &msg); // Add notes about minimum levels and what the user should do here: err.note(&format!("the minimum lint level for `{}` is `{}`", name, min_level.as_str())) @@ -415,7 +415,7 @@ impl<'a> LintLevelsBuilder<'a> { .help(&format!("remove the #[{}({})] directive", level_str, name)); // If it is a future compat lint, warn the user about it. - crate::lint::check_future_compatibility(self.sess, lint, &mut err, Some(name)); + rustc::lint::check_future_compatibility(self.sess, lint, &mut err, Some(name)); err.emit(); } diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index 2e45e2f2312d6..3794e32e7ead3 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -50,7 +50,7 @@ impl Level { } } - fn level_to_flag(self) -> &'static str { + pub fn level_to_flag(self) -> &'static str { match self { Level::Warn => "-W", Level::Deny => "-D", @@ -115,6 +115,7 @@ impl Lint { Lint { name: "", default_level: Level::Forbid, + min_level: Level::Allow, desc: "", edition_lint_opts: None, is_plugin: false, diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 6612558f32cbc..8624d67ab0020 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -80,6 +80,7 @@ declare_lint! { } declare_lint! { + pub DEAD_CODE, Warn, "detect unused, unexported items" } From ce68bd4681a92902abed3b6020d2a4e53370406c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 23 Jan 2020 20:28:12 -0500 Subject: [PATCH 4/6] Make output match master --- src/librustc/lint.rs | 25 +++++++++++++++---------- src/librustc_session/lint.rs | 14 ++++++++++++++ src/librustc_session/lint/builtin.rs | 4 ++-- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs index dbb0152b2a993..28a47e9ccf14e 100644 --- a/src/librustc/lint.rs +++ b/src/librustc/lint.rs @@ -238,7 +238,7 @@ pub fn struct_lint_level<'a>( let diag_msg_id = DiagnosticMessageId::from(lint); let pre_warn_level = match src { LintSource::Default => { - let msg = &format!("#[{}({})] on by default", orig_level.as_str(), name); + let msg = &format!("`#[{}({})]` on by default", orig_level.as_str(), name); sess.diag_note_once(&mut err, diag_msg_id, msg); None } @@ -265,7 +265,7 @@ pub fn struct_lint_level<'a>( if lint_attr_name.as_str() != name { let level_str = orig_level.as_str(); let msg = format!( - "#[{}({})] implied by #[{}({})]", + "`#[{}({})]` implied by `#[{}({})]`", level_str, name, level_str, lint_attr_name ); sess.diag_note_once(&mut err, diag_msg_id, &msg); @@ -313,19 +313,24 @@ pub fn check_future_compatibility<'a>( and may become a hard error in the future", ); } else { - let previously_msg = if let Some(n) = name { - format!("`{}` was previously accepted by the compiler but is being phased out", n) - } else { - format!("this was previously accepted by the compiler but is being phased out") - }; - err.warn(&previously_msg); - let hard_err_msg = if let Some(edition) = future_incompatible.edition { format!("it will become a hard error in the {} edition!", edition) } else { format!("it will become a hard error in a future release!") }; - err.warn(&hard_err_msg); + + let previously_msg = if let Some(n) = name { + format!( + "`{}` was previously accepted by the compiler but is being phased out; {}", + n, hard_err_msg + ) + } else { + format!( + "this was previously accepted by the compiler but is being phased out; {}", + hard_err_msg + ) + }; + err.warn(&previously_msg); } err.note(&format!("for more information, see {}", future_incompatible.reference)); diff --git a/src/librustc_session/lint.rs b/src/librustc_session/lint.rs index 3794e32e7ead3..138d9e44dbd0e 100644 --- a/src/librustc_session/lint.rs +++ b/src/librustc_session/lint.rs @@ -343,6 +343,20 @@ macro_rules! declare_unsuppressable_lint { report_in_external_macro: false, }; }; + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + $(@future_incompatible = $fi:expr;)? $($v:ident),*) => ( + $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { + name: stringify!($NAME), + default_level: $crate::lint::$Level, + min_level: $crate::lint::Warn, + desc: $desc, + edition_lint_opts: None, + is_plugin: false, + $($v: true,)* + $(future_incompatible: Some($fi),)* + ..$crate::lint::Lint::default_fields_for_macro() + }; + ); } #[macro_export] diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs index 8624d67ab0020..c4e69da3a2611 100644 --- a/src/librustc_session/lint/builtin.rs +++ b/src/librustc_session/lint/builtin.rs @@ -5,7 +5,7 @@ //! lints are all available in `rustc_lint::builtin`. use crate::lint::FutureIncompatibleInfo; -use crate::{declare_lint, declare_lint_pass}; +use crate::{declare_lint, declare_lint_pass, declare_unsuppressable_lint}; use rustc_span::edition::Edition; declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` @@ -320,7 +320,7 @@ declare_lint! { }; } -declare_lint! { // FIXME(centril): consider using `declare_unsuppressable_lint` +declare_unsuppressable_lint! { pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, Warn, "floating-point literals cannot be used in patterns", From a8b2c5c3a8ae5ce4cc6ecba89841eea8602d4e3b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 23 Jan 2020 20:46:09 -0500 Subject: [PATCH 5/6] Update stderr files --- ...alf-open-range-pats-exhaustive-fail.stderr | 43 +++++++ ...lf-open-range-pats-hair-lower-empty.stderr | 43 +++++++ .../non-exhaustive-float-range-match.stderr | 79 ++++++++++++ .../usefulness/non-exhaustive-match.stderr | 115 ++++++++++++++++++ 4 files changed, 280 insertions(+) diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr index 26d0cf9e9ecba..c04297f0d3f0d 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr @@ -1,3 +1,19 @@ +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:14 + | +LL | m!(0f32, core::f32::NEG_INFINITY..); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/half-open-range-pats-exhaustive-fail.rs:5:10 + | +LL | #![allow(illegal_floating_point_literal_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[warn(illegal_floating_point_literal_pattern)] is the minimum lint level + = note: the lint level cannot be reduced to `allow` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8 | @@ -6,6 +22,15 @@ LL | m!(0f32, core::f32::NEG_INFINITY..); | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-exhaustive-fail.rs:17:16 + | +LL | m!(0f32, ..core::f32::INFINITY); + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:17:8 | @@ -542,6 +567,24 @@ LL | m!(0, ..VAL_1 | VAL_2..); | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-exhaustive-fail.rs:16:14 + | +LL | m!(0f32, core::f32::NEG_INFINITY..); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-exhaustive-fail.rs:17:16 + | +LL | m!(0f32, ..core::f32::INFINITY); + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error: aborting due to 68 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.stderr index b536e1b5548d0..acbd379878358 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-hair-lower-empty.stderr @@ -58,12 +58,37 @@ error[E0579]: lower range bound must be less than upper LL | m!(0, ..core::i128::MIN); | ^^^^^^^^^^^^^^^^^ +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-hair-lower-empty.rs:44:16 + | +LL | m!(0f32, ..core::f32::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/half-open-range-pats-hair-lower-empty.rs:3:10 + | +LL | #![allow(illegal_floating_point_literal_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[warn(illegal_floating_point_literal_pattern)] is the minimum lint level + = note: the lint level cannot be reduced to `allow` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-hair-lower-empty.rs:44:14 | LL | m!(0f32, ..core::f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-hair-lower-empty.rs:47:16 + | +LL | m!(0f64, ..core::f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-hair-lower-empty.rs:47:14 | @@ -136,12 +161,30 @@ error[E0579]: lower range bound must be less than upper LL | m!(0, ..core::i128::MIN); | ^^^^^^^^^^^^^^^^^ +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-hair-lower-empty.rs:44:16 + | +LL | m!(0f32, ..core::f32::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-hair-lower-empty.rs:44:14 | LL | m!(0f32, ..core::f32::NEG_INFINITY); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: floating-point types cannot be used in patterns + --> $DIR/half-open-range-pats-hair-lower-empty.rs:47:16 + | +LL | m!(0f64, ..core::f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0579]: lower range bound must be less than upper --> $DIR/half-open-range-pats-hair-lower-empty.rs:47:14 | diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr index 6de615c3de4fd..38fafb1774983 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-float-range-match.stderr @@ -1,3 +1,46 @@ +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:6:7 + | +LL | 0.0..=1.0 => {} + | ^^^ + | +note: lint level defined here + --> $DIR/non-exhaustive-float-range-match.rs:1:10 + | +LL | #![allow(illegal_floating_point_literal_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[warn(illegal_floating_point_literal_pattern)] is the minimum lint level + = note: the lint level cannot be reduced to `allow` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:6:13 + | +LL | 0.0..=1.0 => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:11:7 + | +LL | 0.0..=1.0 => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:11:13 + | +LL | 0.0..=1.0 => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/non-exhaustive-float-range-match.rs:10:11 | @@ -6,6 +49,42 @@ LL | match 0.0 { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:6:7 + | +LL | 0.0..=1.0 => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:6:13 + | +LL | 0.0..=1.0 => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:11:7 + | +LL | 0.0..=1.0 => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-float-range-match.rs:11:13 + | +LL | 0.0..=1.0 => {} + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error: aborting due to previous error For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index a06ad5788515c..899f2db0640d0 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -66,6 +66,67 @@ LL | match *vec { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:47:10 + | +LL | [0.1, 0.2, 0.3] => (), + | ^^^ + | +note: lint level defined here + --> $DIR/non-exhaustive-match.rs:1:10 + | +LL | #![allow(illegal_floating_point_literal_pattern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: #[warn(illegal_floating_point_literal_pattern)] is the minimum lint level + = note: the lint level cannot be reduced to `allow` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:47:15 + | +LL | [0.1, 0.2, 0.3] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:47:20 + | +LL | [0.1, 0.2, 0.3] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:48:10 + | +LL | [0.1, 0.2] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:48:15 + | +LL | [0.1, 0.2] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:49:10 + | +LL | [0.1] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered --> $DIR/non-exhaustive-match.rs:46:11 | @@ -74,6 +135,60 @@ LL | match *vec { | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:47:10 + | +LL | [0.1, 0.2, 0.3] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:47:15 + | +LL | [0.1, 0.2, 0.3] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:47:20 + | +LL | [0.1, 0.2, 0.3] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:48:10 + | +LL | [0.1, 0.2] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:48:15 + | +LL | [0.1, 0.2] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + +warning: floating-point types cannot be used in patterns + --> $DIR/non-exhaustive-match.rs:49:10 + | +LL | [0.1] => (), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #41620 + error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0004`. From b7f4d8a4627b3b7105ae40ce777aaaf36db106a8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 23 Jan 2020 21:02:45 -0500 Subject: [PATCH 6/6] Remove unused variable --- src/librustc/lint.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/lint.rs b/src/librustc/lint.rs index 28a47e9ccf14e..a2d875f669b19 100644 --- a/src/librustc/lint.rs +++ b/src/librustc/lint.rs @@ -212,7 +212,6 @@ pub fn struct_lint_level<'a>( }; // 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