Skip to content

Commit a1d1407

Browse files
committed
Add support for declaring 'const fn'
Add a new feature to enable this, since `const extern fn` support is unstable
1 parent ff63cb5 commit a1d1407

File tree

5 files changed

+99
-12
lines changed

5 files changed

+99
-12
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ std = []
2828
align = []
2929
rustc-dep-of-std = ['align', 'rustc-std-workspace-core']
3030
extra_traits = []
31+
const-extern-fn = []
3132
# use_std is deprecated, use `std` instead
3233
use_std = [ 'std' ]
3334

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ libc = "0.2"
3535
* `extra_traits`: all `struct`s implemented in `libc` are `Copy` and `Clone`.
3636
This feature derives `Debug`, `Eq`, `Hash`, and `PartialEq`.
3737

38+
* `const-extern-fn`: Changes some `extern fn`s into `const extern fn`s.
39+
This features requires a nightly rustc
40+
3841
* **deprecated**: `use_std` is deprecated, and is equivalent to `std`.
3942

4043
## Rust version support

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#![no_std]
3535
#![cfg_attr(feature = "rustc-dep-of-std", no_core)]
3636
#![cfg_attr(target_os = "redox", feature(static_nobundle))]
37+
#![cfg_attr(feature = "const-extern-fn", feature(const_extern_fn))]
3738

3839
#[macro_use]
3940
mod macros;

src/macros.rs

+89-9
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,96 @@ macro_rules! s_no_extra_traits {
121121
);
122122
}
123123

124-
#[allow(unused_macros)]
125-
macro_rules! f {
126-
($(pub fn $i:ident($($arg:ident: $argty:ty),*) -> $ret:ty {
127-
$($body:stmt);*
128-
})*) => ($(
129-
#[inline]
130-
pub unsafe extern fn $i($($arg: $argty),*) -> $ret {
131-
$($body);*
124+
// This is a pretty horrible hack to allow us to conditionally mark
125+
// some functions as 'const', without requiring users of this macro
126+
// to care about the "const-extern-fn" feature.
127+
//
128+
// When 'const-extern-fn' is enabled, we emit the captured 'const' keyword
129+
// in the expanded function.
130+
//
131+
// When 'const-extern-fn' is disabled, we always emit a plain 'pub unsafe extern fn'.
132+
// Note that the expression matched by the macro is exactly the same - this allows
133+
// users of this macro to work whether or not 'const-extern-fn' is enabled
134+
//
135+
// Unfortunately, we need to duplicate most of this macro between the 'cfg_if' blocks.
136+
// This is because 'const unsafe extern fn' won't even parse on older compilers,
137+
// so we need to avoid emitting it at all of 'const-extern-fn'.
138+
//
139+
// Specifically, moving the 'cfg_if' into the macro body will *not* work.
140+
// Doing so would cause the '#[cfg(feature = "const-extern-fn")]' to be emiited
141+
// into user code. The 'cfg' gate will not stop Rust from trying to parse the
142+
// 'pub const unsafe extern fn', so users would get a compiler error even when
143+
// the 'const-extern-fn' feature is disabled
144+
//
145+
// Note that users of this macro need to place 'const' in a weird position
146+
// (after the closing ')' for the arguments, but before the return type).
147+
// This was the only way I could satisfy the following two requirements:
148+
// 1. Avoid ambuguity errors from 'macro_rules!' (which happen when writing '$foo:ident fn'
149+
// 2. Allow users of this macro to mix 'pub fn foo' and 'pub const fn bar' within the same
150+
// 'f!' block
151+
cfg_if! {
152+
if #[cfg(feature = "const-extern-fn")] {
153+
#[allow(unused_macros)]
154+
macro_rules! f {
155+
($(pub $({$constness:ident})* fn $i:ident(
156+
$($arg:ident: $argty:ty),*
157+
) -> $ret:ty {
158+
$($body:stmt);*
159+
})*) => ($(
160+
#[inline]
161+
pub $($constness)* unsafe extern fn $i($($arg: $argty),*
162+
) -> $ret {
163+
$($body);*
164+
}
165+
)*)
132166
}
133-
)*)
167+
168+
#[allow(unused_macros)]
169+
macro_rules! const_fn {
170+
($($({$constness:ident})* fn $i:ident(
171+
$($arg:ident: $argty:ty),*
172+
) -> $ret:ty {
173+
$($body:stmt);*
174+
})*) => ($(
175+
#[inline]
176+
$($constness)* fn $i($($arg: $argty),*
177+
) -> $ret {
178+
$($body);*
179+
}
180+
)*)
181+
}
182+
183+
} else {
184+
#[allow(unused_macros)]
185+
macro_rules! f {
186+
($(pub $({$constness:ident})* fn $i:ident(
187+
$($arg:ident: $argty:ty),*
188+
) -> $ret:ty {
189+
$($body:stmt);*
190+
})*) => ($(
191+
#[inline]
192+
pub unsafe extern fn $i($($arg: $argty),*
193+
) -> $ret {
194+
$($body);*
195+
}
196+
)*)
197+
}
198+
199+
#[allow(unused_macros)]
200+
macro_rules! const_fn {
201+
($($({$constness:ident})* fn $i:ident(
202+
$($arg:ident: $argty:ty),*
203+
) -> $ret:ty {
204+
$($body:stmt);*
205+
})*) => ($(
206+
#[inline]
207+
fn $i($($arg: $argty),*
208+
) -> $ret {
209+
$($body);*
210+
}
211+
)*)
212+
}
213+
}
134214
}
135215

136216
#[allow(unused_macros)]

src/unix/linux_like/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1165,8 +1165,10 @@ pub const ARPHRD_IEEE802154: u16 = 804;
11651165
pub const ARPHRD_VOID: u16 = 0xFFFF;
11661166
pub const ARPHRD_NONE: u16 = 0xFFFE;
11671167

1168-
fn CMSG_ALIGN(len: usize) -> usize {
1169-
len + ::mem::size_of::<usize>() - 1 & !(::mem::size_of::<usize>() - 1)
1168+
const_fn! {
1169+
{const} fn CMSG_ALIGN(len: usize) -> usize {
1170+
len + ::mem::size_of::<usize>() - 1 & !(::mem::size_of::<usize>() - 1)
1171+
}
11701172
}
11711173

11721174
f! {
@@ -1182,7 +1184,7 @@ f! {
11821184
cmsg.offset(1) as *mut ::c_uchar
11831185
}
11841186

1185-
pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint {
1187+
pub {const} fn CMSG_SPACE(length: ::c_uint) -> ::c_uint {
11861188
(CMSG_ALIGN(length as usize) + CMSG_ALIGN(::mem::size_of::<cmsghdr>()))
11871189
as ::c_uint
11881190
}

0 commit comments

Comments
 (0)