Skip to content

Commit 4f1be92

Browse files
committed
Auto merge of #129753 - folkertdev:stabilize-const-extern-fn, r=RalfJung
stabilize `const_extern_fn` closes#64926 tracking issue: #64926 reference PR: rust-lang/reference#1596 ## Stabilizaton Report ### Summary Using `const extern "Rust"` and `const extern "C"` was already stabilized (since version 1.62.0, see #95346). This PR stabilizes the other calling conventions: it is now possible to write `const unsafe extern "calling-convention" fn` and `const extern "calling-convention" fn` for any supported calling convention: ```rust const extern "C-unwind" fn foo1(val: u8) -> u8 { val + 1} const extern "stdcall" fn foo2(val: u8) -> u8 { val + 1} const unsafe extern "C-unwind" fn bar1(val: bool) -> bool { !val } const unsafe extern "stdcall" fn bar2(val: bool) -> bool { !val } ``` This can be used to const-ify an `extern fn`, or conversely, to make a `const fn` callable from external code. r? T-lang cc `@RalfJung`
2 parents 9b72238 + a528f4e commit 4f1be92

29 files changed

Lines changed: 186 additions & 235 deletions

‎compiler/rustc_ast_passes/src/feature_gate.rs‎

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -75,22 +75,9 @@ struct PostExpansionVisitor<'a> {
7575

7676
impl<'a>PostExpansionVisitor<'a>{
7777
#[allow(rustc::untranslatable_diagnostic)]// FIXME: make this translatable
78-
fncheck_abi(&self,abi: ast::StrLit,constness: ast::Const){
78+
fncheck_abi(&self,abi: ast::StrLit){
7979
let ast::StrLit{ symbol_unescaped, span, .. } = abi;
8080

81-
iflet ast::Const::Yes(_) = constness {
82-
match symbol_unescaped {
83-
// Stable
84-
sym::Rust | sym::C => {}
85-
abi => gate!(
86-
&self,
87-
const_extern_fn,
88-
span,
89-
format!("`{}` as a `const fn` ABI is unstable", abi)
90-
),
91-
}
92-
}
93-
9481
match abi::is_enabled(self.features, span, symbol_unescaped.as_str()){
9582
Ok(()) => (),
9683
Err(abi::AbiDisabled::Unstable{ feature, explain }) => {
@@ -110,9 +97,9 @@ impl<'a> PostExpansionVisitor<'a> {
11097
}
11198
}
11299

113-
fncheck_extern(&self,ext: ast::Extern,constness: ast::Const){
100+
fncheck_extern(&self,ext: ast::Extern){
114101
iflet ast::Extern::Explicit(abi, _) = ext {
115-
self.check_abi(abi, constness);
102+
self.check_abi(abi);
116103
}
117104
}
118105

@@ -239,7 +226,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
239226
match&i.kind{
240227
ast::ItemKind::ForeignMod(foreign_module) => {
241228
ifletSome(abi) = foreign_module.abi{
242-
self.check_abi(abi, ast::Const::No);
229+
self.check_abi(abi);
243230
}
244231
}
245232

@@ -341,7 +328,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
341328
match&ty.kind{
342329
ast::TyKind::BareFn(bare_fn_ty) => {
343330
// Function pointers cannot be `const`
344-
self.check_extern(bare_fn_ty.ext, ast::Const::No);
331+
self.check_extern(bare_fn_ty.ext);
345332
self.check_late_bound_lifetime_defs(&bare_fn_ty.generic_params);
346333
}
347334
ast::TyKind::Never => {
@@ -446,7 +433,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
446433
fnvisit_fn(&mutself,fn_kind:FnKind<'a>,span:Span, _:NodeId){
447434
ifletSome(header) = fn_kind.header(){
448435
// Stability of const fn methods are covered in `visit_assoc_item` below.
449-
self.check_extern(header.ext, header.constness);
436+
self.check_extern(header.ext);
450437
}
451438

452439
ifletFnKind::Closure(ast::ClosureBinder::For{ generic_params, .. }, ..) = fn_kind {

‎compiler/rustc_feature/src/accepted.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ declare_features! (
115115
(accepted, conservative_impl_trait,"1.26.0",Some(34511)),
116116
/// Allows calling constructor functions in `const fn`.
117117
(accepted, const_constructor,"1.40.0",Some(61456)),
118+
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
119+
(accepted, const_extern_fn,"CURRENT_RUSTC_VERSION",Some(64926)),
118120
/// Allows basic arithmetic on floating point types in a `const fn`.
119121
(accepted, const_fn_floating_point_arithmetic,"1.82.0",Some(57241)),
120122
/// Allows using and casting function pointers in a `const fn`.

‎compiler/rustc_feature/src/unstable.rs‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,6 @@ declare_features! (
401401
(unstable, const_async_blocks,"1.53.0",Some(85368)),
402402
/// Allows `const || {}` closures in const contexts.
403403
(incomplete, const_closures,"1.68.0",Some(106003)),
404-
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
405-
(unstable, const_extern_fn,"1.40.0",Some(64926)),
406404
/// Allows `for _ in _` loops in const contexts.
407405
(unstable, const_for,"1.56.0",Some(87575)),
408406
/// Allows using `&mut` in constant functions.

‎compiler/rustc_parse/src/parser/ty.rs‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -607,9 +607,6 @@ impl<'a> Parser<'a> {
607607
let decl = self.parse_fn_decl(|_| false,AllowPlus::No, recover_return_sign)?;
608608
let whole_span = lo.to(self.prev_token.span);
609609
iflet ast::Const::Yes(span) = constness {
610-
// If we ever start to allow `const fn()`, then update
611-
// feature gating for `#![feature(const_extern_fn)]` to
612-
// cover it.
613610
self.dcx().emit_err(FnPointerCannotBeConst{span: whole_span,qualifier: span });
614611
}
615612
ifletSome(ast::CoroutineKind::Async{ span, .. }) = coroutine_kind {

‎src/tools/clippy/clippy_config/src/msrvs.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ macro_rules! msrv_aliases {
1717

1818
// names may refer to stabilized feature flags or library items
1919
msrv_aliases!{
20+
1,83,0{CONST_EXTERN_FN}
2021
1,83,0{CONST_FLOAT_BITS_CONV}
2122
1,81,0{LINT_REASONS_STABILIZATION}
2223
1,80,0{BOX_INTO_ITER}
@@ -27,7 +28,7 @@ msrv_aliases! {
2728
1,68,0{PATH_MAIN_SEPARATOR_STR}
2829
1,65,0{LET_ELSE,POINTER_CAST_CONSTNESS}
2930
1,63,0{CLONE_INTO}
30-
1,62,0{BOOL_THEN_SOME,DEFAULT_ENUM_ATTRIBUTE,CONST_EXTERN_FN}
31+
1,62,0{BOOL_THEN_SOME,DEFAULT_ENUM_ATTRIBUTE,CONST_EXTERN_C_FN}
3132
1,59,0{THREAD_LOCAL_CONST_INIT}
3233
1,58,0{FORMAT_ARGS_CAPTURE,PATTERN_TRAIT_CHAR_ARRAY,CONST_RAW_PTR_DEREF}
3334
1,56,0{CONST_FN_UNION}

‎src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
119119
.iter()
120120
.any(|param| matches!(param.kind,GenericParamKind::Const{ .. }));
121121

122-
ifalready_const(header)
123-
|| has_const_generic_params
124-
|| !could_be_const_with_abi(cx,&self.msrv, header.abi)
122+
ifalready_const(header) || has_const_generic_params || !could_be_const_with_abi(&self.msrv, header.abi)
125123
{
126124
return;
127125
}
@@ -183,13 +181,13 @@ fn already_const(header: hir::FnHeader) -> bool {
183181
header.constness == Constness::Const
184182
}
185183

186-
fncould_be_const_with_abi(cx:&LateContext<'_>,msrv:&Msrv,abi:Abi) -> bool{
184+
fncould_be_const_with_abi(msrv:&Msrv,abi:Abi) -> bool{
187185
match abi {
188186
Abi::Rust => true,
189187
// `const extern "C"` was stabilized after 1.62.0
190-
Abi::C{unwind:false} => msrv.meets(msrvs::CONST_EXTERN_FN),
188+
Abi::C{unwind:false} => msrv.meets(msrvs::CONST_EXTERN_C_FN),
191189
// Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
192-
_ => cx.tcx.features().const_extern_fn,
190+
_ => msrv.meets(msrvs::CONST_EXTERN_FN),
193191
}
194192
}
195193

‎src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,6 @@ mod msrv {
186186
extern"C"fnc(){}
187187
}
188188

189-
mod with_extern {
190-
extern"C-unwind"fnc_unwind(){}
191-
extern"system"fnsystem(){}
192-
extern"system-unwind"fnsystem_unwind(){}
193-
}
194-
195189
mod with_ty_alias {
196190
typeFoo = impl std::fmt::Debug;
197191

‎src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![warn(clippy::missing_const_for_fn)]
22
#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
3+
#![allow(unsupported_calling_conventions)]
34
#![feature(const_mut_refs)]
45
#![feature(const_trait_impl)]
56

@@ -204,3 +205,16 @@ mod with_ty_alias {
204205
// in this test.
205206
const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {}
206207
}
208+
209+
mod extern_fn {
210+
const extern "C-unwind" fn c_unwind() {}
211+
//~^ ERROR: this could be a `const fn`
212+
const extern "system" fn system() {}
213+
//~^ ERROR: this could be a `const fn`
214+
const extern "system-unwind" fn system_unwind() {}
215+
//~^ ERROR: this could be a `const fn`
216+
pub const extern "stdcall" fn std_call() {}
217+
//~^ ERROR: this could be a `const fn`
218+
pub const extern "stdcall-unwind" fn std_call_unwind() {}
219+
//~^ ERROR: this could be a `const fn`
220+
}

‎src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![warn(clippy::missing_const_for_fn)]
22
#![allow(incomplete_features, clippy::let_and_return, clippy::missing_transmute_annotations)]
3+
#![allow(unsupported_calling_conventions)]
34
#![feature(const_mut_refs)]
45
#![feature(const_trait_impl)]
56

@@ -204,3 +205,16 @@ mod with_ty_alias {
204205
// in this test.
205206
fnalias_ty_is_projection(bar: <()asFooTrait>::Foo){}
206207
}
208+
209+
mod extern_fn {
210+
extern"C-unwind"fnc_unwind(){}
211+
//~^ ERROR: this could be a `const fn`
212+
extern"system"fnsystem(){}
213+
//~^ ERROR: this could be a `const fn`
214+
extern"system-unwind"fnsystem_unwind(){}
215+
//~^ ERROR: this could be a `const fn`
216+
pubextern"stdcall"fnstd_call(){}
217+
//~^ ERROR: this could be a `const fn`
218+
pubextern"stdcall-unwind"fnstd_call_unwind(){}
219+
//~^ ERROR: this could be a `const fn`
220+
}

0 commit comments

Comments
 (0)