Skip to content

Commit c4ef228

Browse files
committed
ctest: test ctest-next in ctest-test
1 parent d2125d0 commit c4ef228

File tree

20 files changed

+242
-62
lines changed

20 files changed

+242
-62
lines changed

.github/workflows/ci.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
# Remove `-Dwarnings` at the MSRV since lints may be different
9090
export RUSTFLAGS=""
9191
# Remove `ctest-next` which uses the 2024 edition
92-
perl -i -ne 'print unless /"ctest-next",/' Cargo.toml
92+
perl -i -ne 'print unless /"ctest-(next|test)",/' Cargo.toml
9393
fi
9494
9595
./ci/verify-build.sh
@@ -320,7 +320,7 @@ jobs:
320320
- name: Install Rust
321321
run: rustup update "$MSRV" --no-self-update && rustup default "$MSRV"
322322
- name: Remove edition 2024 crates
323-
run: perl -i -ne 'print unless /"ctest-next",/' Cargo.toml
323+
run: perl -i -ne 'print unless /"ctest-(next|test)",/' Cargo.toml
324324
- uses: Swatinem/rust-cache@v2
325325
- run: cargo build -p ctest
326326

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ctest-next/src/ast/function.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub struct Fn {
99
#[expect(unused)]
1010
pub(crate) abi: Abi,
1111
pub(crate) ident: BoxStr,
12+
pub(crate) link_name: Option<BoxStr>,
1213
#[expect(unused)]
1314
pub(crate) parameters: Vec<Parameter>,
1415
#[expect(unused)]
@@ -20,4 +21,9 @@ impl Fn {
2021
pub fn ident(&self) -> &str {
2122
&self.ident
2223
}
24+
25+
/// Return the name of the function to be linked C side with.
26+
pub fn link_name(&self) -> Option<&str> {
27+
self.link_name.as_deref()
28+
}
2329
}

ctest-next/src/ast/static_variable.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub struct Static {
1010
#[expect(unused)]
1111
pub(crate) abi: Abi,
1212
pub(crate) ident: BoxStr,
13+
pub(crate) link_name: Option<BoxStr>,
1314
pub(crate) ty: syn::Type,
1415
}
1516

@@ -18,4 +19,9 @@ impl Static {
1819
pub fn ident(&self) -> &str {
1920
&self.ident
2021
}
22+
23+
/// Return the name of the function to be linked C side with.
24+
pub fn link_name(&self) -> Option<&str> {
25+
self.link_name.as_deref()
26+
}
2127
}

ctest-next/src/ffi_items.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::Deref;
33
use syn::punctuated::Punctuated;
44
use syn::visit::Visit;
55

6-
use crate::{Abi, Const, Field, Fn, Parameter, Static, Struct, Type, Union};
6+
use crate::{Abi, BoxStr, Const, Field, Fn, Parameter, Static, Struct, Type, Union};
77

88
/// Represents a collected set of top-level Rust items relevant to FFI generation or analysis.
99
///
@@ -94,6 +94,26 @@ fn collect_fields(fields: &Punctuated<syn::Field, syn::Token![,]>) -> Vec<Field>
9494
.collect()
9595
}
9696

97+
fn extract_single_link_name(attrs: &[syn::Attribute]) -> Option<BoxStr> {
98+
let mut link_name_iter = attrs
99+
.iter()
100+
.filter(|attr| attr.path().is_ident("link_name"));
101+
102+
let link_name = link_name_iter.next()?;
103+
if let Some(attr) = link_name_iter.next() {
104+
panic!("multiple `#[link_name = ...]` attributes found: {attr:?}");
105+
}
106+
107+
if let syn::Meta::NameValue(nv) = &link_name.meta
108+
&& let syn::Expr::Lit(expr_lit) = &nv.value
109+
&& let syn::Lit::Str(lit_str) = &expr_lit.lit
110+
{
111+
return Some(lit_str.value().into_boxed_str());
112+
}
113+
114+
panic!("unrecognized `link_name` syntax: {link_name:?}");
115+
}
116+
97117
fn visit_foreign_item_fn(table: &mut FfiItems, i: &syn::ForeignItemFn, abi: &Abi) {
98118
let public = is_visible(&i.vis);
99119
let abi = abi.clone();
@@ -121,11 +141,13 @@ fn visit_foreign_item_fn(table: &mut FfiItems, i: &syn::ForeignItemFn, abi: &Abi
121141
syn::ReturnType::Default => None,
122142
syn::ReturnType::Type(_, ty) => Some(ty.deref().clone()),
123143
};
144+
let link_name = extract_single_link_name(&i.attrs);
124145

125146
table.foreign_functions.push(Fn {
126147
public,
127148
abi,
128149
ident,
150+
link_name,
129151
parameters,
130152
return_type,
131153
});
@@ -136,11 +158,13 @@ fn visit_foreign_item_static(table: &mut FfiItems, i: &syn::ForeignItemStatic, a
136158
let abi = abi.clone();
137159
let ident = i.ident.to_string().into_boxed_str();
138160
let ty = i.ty.deref().clone();
161+
let link_name = extract_single_link_name(&i.attrs);
139162

140163
table.foreign_statics.push(Static {
141164
public,
142165
abi,
143166
ident,
167+
link_name,
144168
ty,
145169
});
146170
}

ctest-next/templates/test.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
mod generated_tests {
1010
#![allow(non_snake_case)]
1111
#![deny(improper_ctypes_definitions)]
12-
use std::ffi::CStr;
12+
use std::ffi::{CStr, c_char};
1313
use std::fmt::{Debug, LowerHex};
1414
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
15+
#[allow(unused_imports)]
1516
use std::{mem, ptr, slice};
1617

1718
use super::*;
@@ -62,7 +63,7 @@ mod generated_tests {
6263

6364
// SAFETY: FFI call returns a valid C string.
6465
let c_val = unsafe {
65-
let c_ptr: *const c_char = unsafe { ctest_const_cstr__{{ const_cstr.id }}() };
66+
let c_ptr: *const c_char = ctest_const_cstr__{{ const_cstr.id }}();
6667
CStr::from_ptr(c_ptr)
6768
};
6869

@@ -89,7 +90,7 @@ mod generated_tests {
8990
};
9091

9192
let c_bytes = unsafe {
92-
let c_ptr: *const T = unsafe { ctest_const__{{ constant.id }}() };
93+
let c_ptr: *const T = ctest_const__{{ constant.id }}();
9394
slice::from_raw_parts(c_ptr.cast::<u8>(), size_of::<T>())
9495
};
9596

ctest-next/tests/input/hierarchy.out.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
mod generated_tests {
77
#![allow(non_snake_case)]
88
#![deny(improper_ctypes_definitions)]
9-
use std::ffi::CStr;
9+
use std::ffi::{CStr, c_char};
1010
use std::fmt::{Debug, LowerHex};
1111
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
12+
#[expect(unused_imports)]
1213
use std::{mem, ptr, slice};
1314

1415
use super::*;
@@ -58,7 +59,7 @@ mod generated_tests {
5859
};
5960

6061
let c_bytes = unsafe {
61-
let c_ptr: *const T = unsafe { ctest_const__ON() };
62+
let c_ptr: *const T = ctest_const__ON();
6263
slice::from_raw_parts(c_ptr.cast::<u8>(), size_of::<T>())
6364
};
6465

ctest-next/tests/input/macro.out.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
mod generated_tests {
77
#![allow(non_snake_case)]
88
#![deny(improper_ctypes_definitions)]
9-
use std::ffi::CStr;
9+
use std::ffi::{CStr, c_char};
1010
use std::fmt::{Debug, LowerHex};
1111
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
12+
#[expect(unused_imports)]
1213
use std::{mem, ptr, slice};
1314

1415
use super::*;

ctest-next/tests/input/simple.out.with-renames.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
mod generated_tests {
77
#![allow(non_snake_case)]
88
#![deny(improper_ctypes_definitions)]
9-
use std::ffi::CStr;
9+
use std::ffi::{CStr, c_char};
1010
use std::fmt::{Debug, LowerHex};
1111
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
12+
#[expect(unused_imports)]
1213
use std::{mem, ptr, slice};
1314

1415
use super::*;
@@ -57,7 +58,7 @@ mod generated_tests {
5758

5859
// SAFETY: FFI call returns a valid C string.
5960
let c_val = unsafe {
60-
let c_ptr: *const c_char = unsafe { ctest_const_cstr__A() };
61+
let c_ptr: *const c_char = ctest_const_cstr__A();
6162
CStr::from_ptr(c_ptr)
6263
};
6364

@@ -80,7 +81,7 @@ mod generated_tests {
8081

8182
// SAFETY: FFI call returns a valid C string.
8283
let c_val = unsafe {
83-
let c_ptr: *const c_char = unsafe { ctest_const_cstr__B() };
84+
let c_ptr: *const c_char = ctest_const_cstr__B();
8485
CStr::from_ptr(c_ptr)
8586
};
8687

ctest-next/tests/input/simple.out.with-skips.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
mod generated_tests {
77
#![allow(non_snake_case)]
88
#![deny(improper_ctypes_definitions)]
9-
use std::ffi::CStr;
9+
use std::ffi::{CStr, c_char};
1010
use std::fmt::{Debug, LowerHex};
1111
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
12+
#[expect(unused_imports)]
1213
use std::{mem, ptr, slice};
1314

1415
use super::*;
@@ -57,7 +58,7 @@ mod generated_tests {
5758

5859
// SAFETY: FFI call returns a valid C string.
5960
let c_val = unsafe {
60-
let c_ptr: *const c_char = unsafe { ctest_const_cstr__A() };
61+
let c_ptr: *const c_char = ctest_const_cstr__A();
6162
CStr::from_ptr(c_ptr)
6263
};
6364

0 commit comments

Comments
 (0)