Skip to content

Commit fd2df74

Browse files
committed
Auto merge of rust-lang#76219 - Mark-Simulacrum:extern-require-abi, r=estebank
Add allow-by-default lint on implicit ABI in extern function pointers and items This adds a new lint, missing_abi, which lints on omitted ABIs on extern blocks, function declarations, and function pointers. It is currently not emitting the best possible diagnostics -- we need to track the span of "extern" at least or do some heuristic searching based on the available spans -- but seems good enough for an initial pass than can be expanded in future PRs. This is a pretty large PR, but mostly due to updating a large number of tests to include ABIs; I can split that into a separate PR if it would be helpful, but test updates are already in dedicated commits.
2 parents 116d1a7 + 4614671 commit fd2df74

File tree

368 files changed

+1233
-1114
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

368 files changed

+1233
-1114
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3896,6 +3896,7 @@ dependencies = [
38963896
"rustc_macros",
38973897
"rustc_serialize",
38983898
"rustc_span",
3899+
"rustc_target",
38993900
"tracing",
39003901
]
39013902

compiler/rustc_ast_lowering/src/item.rs

+24-14
Original file line numberDiff line numberDiff line change
@@ -310,19 +310,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
310310
);
311311
let sig = hir::FnSig {
312312
decl,
313-
header: this.lower_fn_header(header),
313+
header: this.lower_fn_header(header, fn_sig_span, id),
314314
span: fn_sig_span,
315315
};
316316
hir::ItemKind::Fn(sig, generics, body_id)
317317
})
318318
}
319319
ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
320-
ItemKind::ForeignMod(ref fm) => hir::ItemKind::ForeignMod {
321-
abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
322-
items: self
323-
.arena
324-
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
325-
},
320+
ItemKind::ForeignMod(ref fm) => {
321+
if fm.abi.is_none() {
322+
self.maybe_lint_missing_abi(span, id, abi::Abi::C);
323+
}
324+
hir::ItemKind::ForeignMod {
325+
abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
326+
items: self
327+
.arena
328+
.alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
329+
}
330+
}
326331
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
327332
ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => {
328333
// We lower
@@ -801,13 +806,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
801806
AssocItemKind::Fn(_, ref sig, ref generics, None) => {
802807
let names = self.lower_fn_params_to_names(&sig.decl);
803808
let (generics, sig) =
804-
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
809+
self.lower_method_sig(generics, sig, trait_item_def_id, false, None, i.id);
805810
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
806811
}
807812
AssocItemKind::Fn(_, ref sig, ref generics, Some(ref body)) => {
808813
let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body));
809814
let (generics, sig) =
810-
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
815+
self.lower_method_sig(generics, sig, trait_item_def_id, false, None, i.id);
811816
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
812817
}
813818
AssocItemKind::TyAlias(_, ref generics, ref bounds, ref default) => {
@@ -877,6 +882,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
877882
impl_item_def_id,
878883
impl_trait_return_allow,
879884
asyncness.opt_return_id(),
885+
i.id,
880886
);
881887

882888
(generics, hir::ImplItemKind::Fn(sig, body_id))
@@ -1270,8 +1276,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
12701276
fn_def_id: LocalDefId,
12711277
impl_trait_return_allow: bool,
12721278
is_async: Option<NodeId>,
1279+
id: NodeId,
12731280
) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
1274-
let header = self.lower_fn_header(sig.header);
1281+
let header = self.lower_fn_header(sig.header, sig.span, id);
12751282
let (generics, decl) = self.add_in_band_defs(
12761283
generics,
12771284
fn_def_id,
@@ -1288,12 +1295,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
12881295
(generics, hir::FnSig { header, decl, span: sig.span })
12891296
}
12901297

1291-
fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
1298+
fn lower_fn_header(&mut self, h: FnHeader, span: Span, id: NodeId) -> hir::FnHeader {
12921299
hir::FnHeader {
12931300
unsafety: self.lower_unsafety(h.unsafety),
12941301
asyncness: self.lower_asyncness(h.asyncness),
12951302
constness: self.lower_constness(h.constness),
1296-
abi: self.lower_extern(h.ext),
1303+
abi: self.lower_extern(h.ext, span, id),
12971304
}
12981305
}
12991306

@@ -1304,10 +1311,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
13041311
})
13051312
}
13061313

1307-
pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi {
1314+
pub(super) fn lower_extern(&mut self, ext: Extern, span: Span, id: NodeId) -> abi::Abi {
13081315
match ext {
13091316
Extern::None => abi::Abi::Rust,
1310-
Extern::Implicit => abi::Abi::C,
1317+
Extern::Implicit => {
1318+
self.maybe_lint_missing_abi(span, id, abi::Abi::C);
1319+
abi::Abi::C
1320+
}
13111321
Extern::Explicit(abi) => self.lower_abi(abi),
13121322
}
13131323
}

compiler/rustc_ast_lowering/src/lib.rs

+25-2
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
5353
use rustc_hir::intravisit;
5454
use rustc_hir::{ConstArg, GenericArg, ParamName};
5555
use rustc_index::vec::{Idx, IndexVec};
56-
use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
56+
use rustc_session::lint::builtin::{BARE_TRAIT_OBJECTS, MISSING_ABI};
57+
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
5758
use rustc_session::parse::ParseSess;
5859
use rustc_session::Session;
5960
use rustc_span::hygiene::ExpnId;
6061
use rustc_span::source_map::{respan, DesugaringKind};
6162
use rustc_span::symbol::{kw, sym, Ident, Symbol};
6263
use rustc_span::Span;
64+
use rustc_target::spec::abi::Abi;
6365

6466
use smallvec::{smallvec, SmallVec};
6567
use std::collections::BTreeMap;
@@ -1288,14 +1290,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12881290
}
12891291
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(&f.generic_params, |this| {
12901292
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
1293+
let span = this.sess.source_map().next_point(t.span.shrink_to_lo());
12911294
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
12921295
generic_params: this.lower_generic_params(
12931296
&f.generic_params,
12941297
&NodeMap::default(),
12951298
ImplTraitContext::disallowed(),
12961299
),
12971300
unsafety: this.lower_unsafety(f.unsafety),
1298-
abi: this.lower_extern(f.ext),
1301+
abi: this.lower_extern(f.ext, span, t.id),
12991302
decl: this.lower_fn_decl(&f.decl, None, false, None),
13001303
param_names: this.lower_fn_params_to_names(&f.decl),
13011304
}))
@@ -2777,6 +2780,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
27772780
)
27782781
}
27792782
}
2783+
2784+
fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId, default: Abi) {
2785+
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
2786+
// call site which do not have a macro backtrace. See #61963.
2787+
let is_macro_callsite = self
2788+
.sess
2789+
.source_map()
2790+
.span_to_snippet(span)
2791+
.map(|snippet| snippet.starts_with("#["))
2792+
.unwrap_or(true);
2793+
if !is_macro_callsite {
2794+
self.resolver.lint_buffer().buffer_lint_with_diagnostic(
2795+
MISSING_ABI,
2796+
id,
2797+
span,
2798+
"extern declarations without an explicit ABI are deprecated",
2799+
BuiltinLintDiagnostics::MissingAbi(span, default),
2800+
)
2801+
}
2802+
}
27802803
}
27812804

27822805
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body<'_>>) -> Vec<hir::BodyId> {

compiler/rustc_error_codes/src/error_codes/E0044.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ You cannot use type or const parameters on foreign items.
33
Example of erroneous code:
44

55
```compile_fail,E0044
6-
extern { fn some_func<T>(x: T); }
6+
extern "C" { fn some_func<T>(x: T); }
77
```
88

99
To fix this, replace the generic parameter with the specializations that you
1010
need:
1111

1212
```
13-
extern { fn some_func_i32(x: i32); }
14-
extern { fn some_func_i64(x: i64); }
13+
extern "C" { fn some_func_i32(x: i32); }
14+
extern "C" { fn some_func_i64(x: i64); }
1515
```

compiler/rustc_error_codes/src/error_codes/E0130.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ A pattern was declared as an argument in a foreign function declaration.
33
Erroneous code example:
44

55
```compile_fail,E0130
6-
extern {
6+
extern "C" {
77
fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign
88
// function declarations
99
}
@@ -17,15 +17,15 @@ struct SomeStruct {
1717
b: u32,
1818
}
1919
20-
extern {
20+
extern "C" {
2121
fn foo(s: SomeStruct); // ok!
2222
}
2323
```
2424

2525
Or:
2626

2727
```
28-
extern {
28+
extern "C" {
2929
fn foo(a: (u32, u32)); // ok!
3030
}
3131
```

compiler/rustc_error_codes/src/error_codes/E0454.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ A link name was given with an empty name.
33
Erroneous code example:
44

55
```compile_fail,E0454
6-
#[link(name = "")] extern {}
6+
#[link(name = "")] extern "C" {}
77
// error: `#[link(name = "")]` given with empty name
88
```
99

1010
The rust compiler cannot link to an external library if you don't give it its
1111
name. Example:
1212

1313
```no_run
14-
#[link(name = "some_lib")] extern {} // ok!
14+
#[link(name = "some_lib")] extern "C" {} // ok!
1515
```

compiler/rustc_error_codes/src/error_codes/E0455.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ as frameworks are specific to that operating system.
44
Erroneous code example:
55

66
```ignore (should-compile_fail-but-cannot-doctest-conditionally-without-macos)
7-
#[link(name = "FooCoreServices", kind = "framework")] extern {}
7+
#[link(name = "FooCoreServices", kind = "framework")] extern "C" {}
88
// OS used to compile is Linux for example
99
```
1010

1111
To solve this error you can use conditional compilation:
1212

1313
```
1414
#[cfg_attr(target="macos", link(name = "FooCoreServices", kind = "framework"))]
15-
extern {}
15+
extern "C" {}
1616
```
1717

1818
Learn more in the [Conditional Compilation][conditional-compilation] section

compiler/rustc_error_codes/src/error_codes/E0458.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ An unknown "kind" was specified for a link attribute.
33
Erroneous code example:
44

55
```compile_fail,E0458
6-
#[link(kind = "wonderful_unicorn")] extern {}
6+
#[link(kind = "wonderful_unicorn")] extern "C" {}
77
// error: unknown kind: `wonderful_unicorn`
88
```
99

compiler/rustc_error_codes/src/error_codes/E0459.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ A link was used without a name parameter.
33
Erroneous code example:
44

55
```compile_fail,E0459
6-
#[link(kind = "dylib")] extern {}
6+
#[link(kind = "dylib")] extern "C" {}
77
// error: `#[link(...)]` specified without `name = "foo"`
88
```
99

1010
Please add the name parameter to allow the rust compiler to find the library
1111
you want. Example:
1212

1313
```no_run
14-
#[link(kind = "dylib", name = "some_lib")] extern {} // ok!
14+
#[link(kind = "dylib", name = "some_lib")] extern "C" {} // ok!
1515
```

compiler/rustc_error_codes/src/error_codes/E0617.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Attempted to pass an invalid type of variable into a variadic function.
33
Erroneous code example:
44

55
```compile_fail,E0617
6-
extern {
6+
extern "C" {
77
fn printf(c: *const i8, ...);
88
}
99
@@ -21,7 +21,7 @@ to import from `std::os::raw`).
2121
In this case, `c_double` has the same size as `f64` so we can use it directly:
2222

2323
```no_run
24-
# extern {
24+
# extern "C" {
2525
# fn printf(c: *const i8, ...);
2626
# }
2727
unsafe {

compiler/rustc_error_codes/src/error_codes/E0633.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Erroneous code example:
66
#![feature(unwind_attributes)]
77
88
#[unwind()] // error: expected one argument
9-
pub extern fn something() {}
9+
pub extern "C" fn something() {}
1010
1111
fn main() {}
1212
```

compiler/rustc_error_codes/src/error_codes/E0724.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ the function inside of an `extern` block.
1818
```
1919
#![feature(ffi_returns_twice)]
2020
21-
extern {
21+
extern "C" {
2222
#[ffi_returns_twice] // ok!
2323
pub fn foo();
2424
}

compiler/rustc_lint/src/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,10 @@ pub trait LintContext: Sized {
600600
BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident) => {
601601
db.span_suggestion(span, "remove `mut` from the parameter", ident.to_string(), Applicability::MachineApplicable);
602602
}
603+
BuiltinLintDiagnostics::MissingAbi(span, default_abi) => {
604+
db.span_label(span, "ABI should be specified here");
605+
db.help(&format!("the default ABI is {}", default_abi.name()));
606+
}
603607
}
604608
// Rewrap `db`, and pass control to the user.
605609
decorate(LintDiagnosticBuilder::new(db));

compiler/rustc_lint_defs/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ rustc_data_structures = { path = "../rustc_data_structures" }
1111
rustc_span = { path = "../rustc_span" }
1212
rustc_serialize = { path = "../rustc_serialize" }
1313
rustc_macros = { path = "../rustc_macros" }
14+
rustc_target = { path = "../rustc_target" }

compiler/rustc_lint_defs/src/builtin.rs

+26
Original file line numberDiff line numberDiff line change
@@ -2917,6 +2917,7 @@ declare_lint_pass! {
29172917
FUNCTION_ITEM_REFERENCES,
29182918
USELESS_DEPRECATED,
29192919
UNSUPPORTED_NAKED_FUNCTIONS,
2920+
MISSING_ABI,
29202921
]
29212922
}
29222923

@@ -2944,3 +2945,28 @@ declare_lint! {
29442945
}
29452946

29462947
declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
2948+
2949+
declare_lint! {
2950+
/// The `missing_abi` lint detects cases where the ABI is omitted from
2951+
/// extern declarations.
2952+
///
2953+
/// ### Example
2954+
///
2955+
/// ```rust,compile_fail
2956+
/// #![deny(missing_abi)]
2957+
///
2958+
/// extern fn foo() {}
2959+
/// ```
2960+
///
2961+
/// {{produces}}
2962+
///
2963+
/// ### Explanation
2964+
///
2965+
/// Historically, Rust implicitly selected C as the ABI for extern
2966+
/// declarations. We expect to add new ABIs, like `C-unwind`, in the future,
2967+
/// though this has not yet happened, and especially with their addition
2968+
/// seeing the ABI easily will make code review easier.
2969+
pub MISSING_ABI,
2970+
Allow,
2971+
"No declared ABI for extern declaration"
2972+
}

compiler/rustc_lint_defs/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_ast::node_id::{NodeId, NodeMap};
66
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
77
use rustc_span::edition::Edition;
88
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
9+
use rustc_target::spec::abi::Abi;
910

1011
pub mod builtin;
1112

@@ -252,6 +253,7 @@ pub enum BuiltinLintDiagnostics {
252253
UnusedImports(String, Vec<(Span, String)>),
253254
RedundantImport(Vec<(Span, bool)>, Ident),
254255
DeprecatedMacro(Option<Symbol>, Span),
256+
MissingAbi(Span, Abi),
255257
UnusedDocComment(Span),
256258
PatternsInFnsWithoutBody(Span, Ident),
257259
}

compiler/rustc_llvm/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub fn initialize_available_targets() {
3838
($cfg:meta, $($method:ident),*) => { {
3939
#[cfg($cfg)]
4040
fn init() {
41-
extern {
41+
extern "C" {
4242
$(fn $method();)*
4343
}
4444
unsafe {

0 commit comments

Comments
 (0)