diff --git a/Cargo.lock b/Cargo.lock index ab452c97e7b..a24ab967e5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3896,6 +3896,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "rustc_target", "tracing", ] diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 4e9f9d66c5b..7666b25b6d7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -317,12 +317,17 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)), - ItemKind::ForeignMod(ref fm) => hir::ItemKind::ForeignMod { - abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)), - items: self - .arena - .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), - }, + ItemKind::ForeignMod(ref fm) => { + if fm.abi.is_none() { + self.maybe_lint_missing_abi(span, id, abi::Abi::C); + } + hir::ItemKind::ForeignMod { + abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)), + items: self + .arena + .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), + } + } ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)), ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => { // We lower diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 89557c29dd1..59e55fc4ee7 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -53,13 +53,15 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; use rustc_hir::intravisit; use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer}; +use rustc_session::lint::builtin::{BARE_TRAIT_OBJECTS, MISSING_ABI}; +use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{respan, DesugaringKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; +use rustc_target::spec::abi::Abi; use smallvec::{smallvec, SmallVec}; use std::collections::BTreeMap; @@ -2777,6 +2779,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } } + + fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId, default: Abi) { + // FIXME(davidtwco): This is a hack to detect macros which produce spans of the + // call site which do not have a macro backtrace. See #61963. + let is_macro_callsite = self + .sess + .source_map() + .span_to_snippet(span) + .map(|snippet| snippet.starts_with("#[")) + .unwrap_or(true); + if !is_macro_callsite { + self.resolver.lint_buffer().buffer_lint_with_diagnostic( + MISSING_ABI, + id, + span, + "extern declarations without an explicit ABI are deprecated", + BuiltinLintDiagnostics::MissingAbi(span, default), + ) + } + } } fn body_ids(bodies: &BTreeMap>) -> Vec { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index f4740be34cb..0f40324acb1 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -600,6 +600,10 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident) => { db.span_suggestion(span, "remove `mut` from the parameter", ident.to_string(), Applicability::MachineApplicable); } + BuiltinLintDiagnostics::MissingAbi(span, default_abi) => { + db.span_label(span, "ABI should be specified here"); + db.help(&format!("the default ABI is {}", default_abi.name())); + } } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml index 7f908088cf5..f909f159784 100644 --- a/compiler/rustc_lint_defs/Cargo.toml +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -11,3 +11,4 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_span = { path = "../rustc_span" } rustc_serialize = { path = "../rustc_serialize" } rustc_macros = { path = "../rustc_macros" } +rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f90fc7fc9ab..e9632796704 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2917,6 +2917,7 @@ declare_lint_pass! { FUNCTION_ITEM_REFERENCES, USELESS_DEPRECATED, UNSUPPORTED_NAKED_FUNCTIONS, + MISSING_ABI, ] } @@ -2944,3 +2945,28 @@ declare_lint! { } declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); + +declare_lint! { + /// The `missing_abi` lint detects cases where the ABI is omitted from + /// extern declarations. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_abi)] + /// + /// extern fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Historically, Rust implicitly selected C as the ABI for extern + /// declarations. We expect to add new ABIs, like `C-unwind`, in the future, + /// though this has not yet happened, and especially with their addition + /// seeing the ABI easily will make code review easier. + pub MISSING_ABI, + Allow, + "No declared ABI for extern declaration" +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 2bfc6a85576..9d60a51a0af 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -6,6 +6,7 @@ use rustc_ast::node_id::{NodeId, NodeMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_span::edition::Edition; use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol}; +use rustc_target::spec::abi::Abi; pub mod builtin; @@ -252,6 +253,7 @@ pub enum BuiltinLintDiagnostics { UnusedImports(String, Vec<(Span, String)>), RedundantImport(Vec<(Span, bool)>, Ident), DeprecatedMacro(Option, Span), + MissingAbi(Span, Abi), UnusedDocComment(Span), PatternsInFnsWithoutBody(Span, Ident), }