diff --git a/CMakeLists.txt b/CMakeLists.txt index ea38b1c1..2dd2157f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ add_custom_command( ) add_subdirectory(cpp2rust) +add_subdirectory(libc-dep) add_subdirectory(libcc2rs) add_subdirectory(tests) diff --git a/libc-dep/CMakeLists.txt b/libc-dep/CMakeLists.txt new file mode 100644 index 00000000..903a6a8c --- /dev/null +++ b/libc-dep/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LIBC_DEP_DIR ${CMAKE_SOURCE_DIR}/libc-dep) +set(LIBC_DEP_OUTPUT ${LIBC_DEP_DIR}/target/release/libc_dep.rlib) + +add_custom_command( + OUTPUT ${LIBC_DEP_OUTPUT} + COMMAND cargo +${RUST_STABLE_VERSION} build --release + WORKING_DIRECTORY ${LIBC_DEP_DIR} + DEPENDS "${RUST_STAMP_FILE}" ${LIBC_DEP_DIR}/Cargo.toml +) + +add_custom_target( + libc_dep ALL + DEPENDS "${LIBC_DEP_OUTPUT}" +) diff --git a/libc-dep/Cargo.toml b/libc-dep/Cargo.toml new file mode 100644 index 00000000..28cb84c3 --- /dev/null +++ b/libc-dep/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "libc-dep" +version = "0.1.0" +edition = "2024" + +[dependencies] +libc = "0.2" diff --git a/libc-dep/src/lib.rs b/libc-dep/src/lib.rs new file mode 100644 index 00000000..e69de29b diff --git a/libcc2rs-macros/Cargo.toml b/libcc2rs-macros/Cargo.toml index 5a895659..0d465af5 100644 --- a/libcc2rs-macros/Cargo.toml +++ b/libcc2rs-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "libcc2rs-macros" version = "0.1.0" -edition = "2021" +edition = "2024" [lib] proc-macro = true diff --git a/libcc2rs-macros/src/goto.rs b/libcc2rs-macros/src/goto.rs index 916fd211..cb8ece18 100644 --- a/libcc2rs-macros/src/goto.rs +++ b/libcc2rs-macros/src/goto.rs @@ -3,7 +3,7 @@ use proc_macro::TokenStream; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Expr, Lifetime, Token}; +use syn::{Expr, Lifetime, Token, parse_macro_input}; use crate::state_machine::{Arm, GotoStateMachine, StateMachine}; diff --git a/libcc2rs-macros/src/switch.rs b/libcc2rs-macros/src/switch.rs index dfb45002..cc17ef10 100644 --- a/libcc2rs-macros/src/switch.rs +++ b/libcc2rs-macros/src/switch.rs @@ -3,7 +3,7 @@ use proc_macro::TokenStream; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Expr, Pat}; +use syn::{Expr, Pat, parse_macro_input}; use crate::state_machine::{Arm, DispatchCase, GotoStateMachine, StateMachine, SwitchStateMachine}; diff --git a/libcc2rs/CMakeLists.txt b/libcc2rs/CMakeLists.txt index 868a869c..8ddaa138 100644 --- a/libcc2rs/CMakeLists.txt +++ b/libcc2rs/CMakeLists.txt @@ -1,21 +1,32 @@ -set(RUST_LIB_DIR ${CMAKE_SOURCE_DIR}/libcc2rs) -set(RUST_MACROS_DIR ${CMAKE_SOURCE_DIR}/libcc2rs-macros) -set(RUST_BUILD_DIR ${CMAKE_BINARY_DIR}/rust) -file(GLOB_RECURSE LIBCC2RS_SOURCE "${RUST_LIB_DIR}/*.rs") -file(GLOB_RECURSE LIBCC2RS_MACROS_SOURCE "${RUST_MACROS_DIR}/*.rs") +set(LIBCC2RC_LIB_DIR ${CMAKE_SOURCE_DIR}/libcc2rs) +set(LIBCC2RC_MACROS_LIB_DIR ${CMAKE_SOURCE_DIR}/libcc2rs-macros) +set(LIBCC2RS_RLIB ${LIBCC2RC_LIB_DIR}/target/release/liblibcc2rs.rlib) +set(LIBCC2RS_MACROS_RLIB ${LIBCC2RC_LIB_DIR}/target/release/liblibcc2rs-macros.rlib) +file(GLOB_RECURSE LIBCC2RS_SOURCES "${LIBCC2RC_LIB_DIR}/src/*.rs") +file(GLOB_RECURSE LIBCC2RS_MACROS_SOURCES "${LIBCC2RC_MACROS_LIB_DIR}/src/*.rs") add_custom_command( - OUTPUT ${RUST_BUILD_DIR}/release/liblibcc2rs.rlib - COMMAND ${CMAKE_COMMAND} -E env CARGO_TARGET_DIR=${RUST_BUILD_DIR} cargo build --release - WORKING_DIRECTORY ${RUST_LIB_DIR} + OUTPUT ${LIBCC2RS_RLIB} + COMMAND cargo +${RUST_STABLE_VERSION} build --release + WORKING_DIRECTORY ${LIBCC2RC_LIB_DIR} DEPENDS - ${LIBCC2RS_SOURCE} - ${LIBCC2RS_MACROS_SOURCE} - ${RUST_LIB_DIR}/Cargo.toml - ${RUST_MACROS_DIR}/Cargo.toml - COMMENT "Building libcc2rs" + "${RUST_STAMP_FILE}" + ${LIBCC2RS_SOURCES} + ${LIBCC2RS_MACROS_SOURCES} + ${LIBCC2RC_LIB_DIR}/Cargo.toml + ${LIBCC2RC_MACROS_LIB_DIR}/Cargo.toml +) + +add_custom_command( + OUTPUT ${LIBCC2RS_MACROS_RLIB} + COMMAND cargo +${RUST_STABLE_VERSION} build --release + WORKING_DIRECTORY ${LIBCC2RC_MACROS_LIB_DIR} + DEPENDS + "${RUST_STAMP_FILE}" + ${LIBCC2RS_MACROS_SOURCES} + ${LIBCC2RC_MACROS_LIB_DIR}/Cargo.toml ) add_custom_target(libcc2rs ALL - DEPENDS ${RUST_BUILD_DIR}/release/liblibcc2rs.rlib "${RUST_STAMP_FILE}" + DEPENDS ${LIBCC2RS_RLIB} ${LIBCC2RS_MACROS_RLIB} ) diff --git a/libcc2rs/Cargo.toml b/libcc2rs/Cargo.toml index 0ce61d9d..afea73ee 100644 --- a/libcc2rs/Cargo.toml +++ b/libcc2rs/Cargo.toml @@ -1,9 +1,7 @@ [package] name = "libcc2rs" version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +edition = "2024" [dependencies] libcc2rs-macros = { path = "../libcc2rs-macros", version = "0.1.0" } diff --git a/libcc2rs/src/compat.rs b/libcc2rs/src/compat.rs index dec6d556..486c260b 100644 --- a/libcc2rs/src/compat.rs +++ b/libcc2rs/src/compat.rs @@ -3,7 +3,7 @@ use std::ffi::c_void; -extern "C" { +unsafe extern "C" { #[cfg(target_os = "linux")] #[link_name = "malloc_usable_size"] fn platform_malloc_size(ptr: *mut c_void) -> usize; @@ -21,10 +21,10 @@ extern "C" { pub unsafe fn malloc_usable_size(ptr: *mut c_void) -> usize { #[cfg(target_os = "linux")] { - platform_malloc_size(ptr) + unsafe { platform_malloc_size(ptr) } } #[cfg(target_os = "macos")] { - platform_malloc_size(ptr as *const c_void) + unsafe { platform_malloc_size(ptr as *const c_void) } } } diff --git a/libcc2rs/src/dec.rs b/libcc2rs/src/dec.rs index c5ad898a..9332d846 100644 --- a/libcc2rs/src/dec.rs +++ b/libcc2rs/src/dec.rs @@ -76,7 +76,7 @@ impl UnsafePostfixDec for *const T { #[inline] unsafe fn postfix_dec(&mut self) -> Self { let copy = *self; - *self = self.offset(-1); + unsafe { *self = self.offset(-1) } copy } } @@ -85,7 +85,7 @@ impl UnsafePostfixDec for *mut T { #[inline] unsafe fn postfix_dec(&mut self) -> Self { let copy = *self; - *self = self.offset(-1); + unsafe { *self = self.offset(-1) } copy } } @@ -100,7 +100,7 @@ pub trait UnsafePrefixDec { impl UnsafePrefixDec for *const T { #[inline] unsafe fn prefix_dec(&mut self) -> Self { - *self = self.offset(-1); + unsafe { *self = self.offset(-1) } *self } } @@ -108,7 +108,7 @@ impl UnsafePrefixDec for *const T { impl UnsafePrefixDec for *mut T { #[inline] unsafe fn prefix_dec(&mut self) -> Self { - *self = self.offset(-1); + unsafe { *self = self.offset(-1) } *self } } diff --git a/libcc2rs/src/inc.rs b/libcc2rs/src/inc.rs index a3433469..b64887c5 100644 --- a/libcc2rs/src/inc.rs +++ b/libcc2rs/src/inc.rs @@ -87,7 +87,7 @@ impl UnsafePostfixInc for *const T { #[inline] unsafe fn postfix_inc(&mut self) -> Self { let copy = *self; - *self = self.offset(1); + unsafe { *self = self.offset(1) } copy } } @@ -96,7 +96,7 @@ impl UnsafePostfixInc for *mut T { #[inline] unsafe fn postfix_inc(&mut self) -> Self { let copy = *self; - *self = self.offset(1); + unsafe { *self = self.offset(1) } copy } } @@ -111,7 +111,7 @@ pub trait UnsafePrefixInc { impl UnsafePrefixInc for *const T { #[inline] unsafe fn prefix_inc(&mut self) -> Self { - *self = self.offset(1); + unsafe { *self = self.offset(1) } *self } } @@ -119,7 +119,7 @@ impl UnsafePrefixInc for *const T { impl UnsafePrefixInc for *mut T { #[inline] unsafe fn prefix_inc(&mut self) -> Self { - *self = self.offset(1); + unsafe { *self = self.offset(1) } *self } } diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index 877e73fd..00c5711e 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -77,7 +77,7 @@ impl fmt::Debug for PtrKind { PtrKind::HeapSingle(w) => write!(f, "HeapSingle({:?})", w.as_ptr()), PtrKind::StackArray(w) => write!(f, "StackArray({:?})", w.as_ptr()), PtrKind::HeapArray(w) => write!(f, "HeapArray({:?})", w.as_ptr()), - PtrKind::Reinterpreted(ref data) => { + PtrKind::Reinterpreted(data) => { write!(f, "Reinterpreted(0x{:x})", data.address()) } } @@ -88,12 +88,12 @@ impl Clone for PtrKind { fn clone(&self) -> Self { match self { PtrKind::Null => PtrKind::Null, - PtrKind::Vec(ref weak) => PtrKind::Vec(weak.clone()), - PtrKind::StackSingle(ref weak) => PtrKind::StackSingle(weak.clone()), - PtrKind::HeapSingle(ref weak) => PtrKind::HeapSingle(weak.clone()), - PtrKind::StackArray(ref weak) => PtrKind::StackArray(weak.clone()), - PtrKind::HeapArray(ref weak) => PtrKind::HeapArray(weak.clone()), - PtrKind::Reinterpreted(ref data) => PtrKind::Reinterpreted(Rc::clone(data)), + PtrKind::Vec(weak) => PtrKind::Vec(weak.clone()), + PtrKind::StackSingle(weak) => PtrKind::StackSingle(weak.clone()), + PtrKind::HeapSingle(weak) => PtrKind::HeapSingle(weak.clone()), + PtrKind::StackArray(weak) => PtrKind::StackArray(weak.clone()), + PtrKind::HeapArray(weak) => PtrKind::HeapArray(weak.clone()), + PtrKind::Reinterpreted(data) => PtrKind::Reinterpreted(Rc::clone(data)), } } } @@ -105,7 +105,7 @@ impl PtrKind { PtrKind::StackSingle(w) | PtrKind::HeapSingle(w) => w.as_ptr() as usize, PtrKind::Vec(w) => w.as_ptr() as usize, PtrKind::StackArray(w) | PtrKind::HeapArray(w) => w.as_ptr() as usize, - PtrKind::Reinterpreted(ref data) => data.address(), + PtrKind::Reinterpreted(data) => data.address(), } } } @@ -346,7 +346,7 @@ impl Ptr { rc: weak.upgrade().expect("ub: dangling pointer"), offset: self.offset, }, - PtrKind::Reinterpreted(ref data) => StrongPtr::Reinterpreted { + PtrKind::Reinterpreted(data) => StrongPtr::Reinterpreted { alloc: Rc::clone(data), byte_offset: self.offset, cell: RefCell::new(None), @@ -416,7 +416,7 @@ impl Ptr { Rc::new(SliceOriginalAlloc { weak: weak.clone() }), self.byte_offset(), ), - PtrKind::Reinterpreted(ref data) => (Rc::clone(data), self.offset), + PtrKind::Reinterpreted(data) => (Rc::clone(data), self.offset), }; Ptr { @@ -879,7 +879,7 @@ impl fmt::Debug for Ptr { .wrapping_add(self.offset.wrapping_mul(std::mem::size_of::())), PtrKind::Vec(w) => (Weak::as_ptr(w) as usize) .wrapping_add(self.offset.wrapping_mul(std::mem::size_of::())), - PtrKind::Reinterpreted(ref data) => data.address().wrapping_add(self.offset), + PtrKind::Reinterpreted(data) => data.address().wrapping_add(self.offset), }; write!(f, "0x{:x}", addr) } @@ -1191,7 +1191,7 @@ impl PtrDyn { pub fn upgrade(&self) -> StrongPtrDyn { match &self.kind { PtrKindDyn::Null => panic!("ub: dereference of null pointer"), - PtrKindDyn::StackSingle(ref weak) => { + PtrKindDyn::StackSingle(weak) => { assert_eq!(self.offset, 0, "ub: invalid offset"); StrongPtrDyn { rc: weak.upgrade().expect("ub: dangling pointer"), diff --git a/tests/lit/lit/formats/Cpp2RustTest.py b/tests/lit/lit/formats/Cpp2RustTest.py index e4df3b55..ed7c46fa 100644 --- a/tests/lit/lit/formats/Cpp2RustTest.py +++ b/tests/lit/lit/formats/Cpp2RustTest.py @@ -74,7 +74,6 @@ class TestContext: skip_run: bool = False build_dir: Optional[Path] = None generated: Optional[str] = None - pkg_name: Optional[str] = None cpp_bin: Optional[Path] = None rust_bin: Optional[Path] = None cpp_result: Optional[RunResult] = None @@ -86,10 +85,10 @@ def setup(cls, test): is_multi = is_multi_file_test(cc_input) model = test.getSourcePath().split("/")[-1] fname = cc_input.name if is_multi else cc_input.stem - tmp_dir = Path("tmp") / f"{fname}-{model}" + tmp_dir = get_temp_dir() / f"{fname}-{model}" shutil.rmtree(tmp_dir, ignore_errors=True) - (tmp_dir / "src").mkdir(parents=True) + tmp_dir.mkdir(parents=True) return cls( cc_input=cc_input, @@ -98,7 +97,7 @@ def setup(cls, test): filepath=cc_input if is_multi else cc_input.parent, model=model, tmp_dir=tmp_dir, - rs_file=tmp_dir / "src" / "main.rs", + rs_file=tmp_dir / "main.rs", expectations=TestExpectations.parse(load_source_text(cc_input), model), replace_expected=bool(os.environ.get("REPLACE_EXPECTED", False)), skip_run=bool(os.environ.get("SKIP_RUN", False)), @@ -178,6 +177,7 @@ def build_cpp(self): self.cpp_bin = self.build_dir / "app" return None + ## FIXME: these must use the detected/chosen compiler in cmake cc = ( os.environ.get("CC", "clang") if self.cc_input.suffix == ".c" @@ -192,35 +192,50 @@ def build_cpp(self): def build_rust(self): exp = self.expectations - self.pkg_name = "test_" + re.sub(r"[^a-zA-Z0-9_]", "_", self.tmp_dir.name) - - (self.tmp_dir / "Cargo.toml").write_text(f""" -[package] -name = "{self.pkg_name}" -version = "0.1.0" -edition = "2021" - -[[bin]] -name = "{self.pkg_name}" -path = "src/main.rs" - -[dependencies] -libc = "0.2.169" -libcc2rs = {{ path = "../../../libcc2rs" }} -""") - - cmd = ["cargo", "+" + read_rust_version(), "build", "--release", "--quiet"] - _, err, returncode = lit.util.executeCommand( - cmd, str(self.tmp_dir), env=cargo_env() + + parent = Path(__file__).resolve().parent.parent.parent.parent.parent + cc2rs_dir = parent / "libcc2rs" / "target" / "release" + # pick the most recently compiled libc + libc_rlib = max( + (parent / "libc-dep" / "target" / "release" / "deps").glob( + "liblibc-*.rlib" + ), + key=lambda p: p.stat().st_mtime, ) + cmd = [ + "rustc", + "+" + read_rust_version(), + "--edition", + "2024", + "main.rs", + "-A", + "warnings", + "-C", + "opt-level=3", # Equivalent to --release + "-C", + "strip=symbols", + "-C", + "panic=abort", + "-W", ## TODO: remove this once we fix the errors in the generated code + "static_mut_refs", + "--out-dir", + str(self.tmp_dir), + "-L", + f"dependency={cc2rs_dir / 'deps'}", + "--extern", + f"libcc2rs={cc2rs_dir / 'liblibcc2rs.rlib'}", + "--extern", + f"libc={libc_rlib}", + ] + _, err, returncode = lit.util.executeCommand(cmd, str(self.tmp_dir)) if exp.should_not_compile: if returncode != 0: return (lit.Test.XFAIL, "") return (exp.fail_code, "expected no-compile but compiled successfully") if returncode != 0: - return (exp.fail_code, "cargo failed\n" + err) + return (exp.fail_code, "rustc failed\n" + err) - self.rust_bin = shared_target_dir() / "release" / self.pkg_name + self.rust_bin = self.tmp_dir / "main" return None def run_cpp(self): @@ -237,10 +252,9 @@ def run_rust(self): if exp.should_panic: err = str(self.rust_result.stderr) - if ( - not re.search(r"thread 'main' \(\d+\) panicked at", err) - or self.rust_result.returncode != 101 - ): + if not re.search( + r"thread 'main' \(\d+\) panicked at", err + ) or self.rust_result.returncode not in [-6, 101]: return (exp.fail_code, "expected panic\n" + err) return self.success_result() @@ -331,12 +345,11 @@ def read_rust_version(): raise Exception("could not find rust version in " + toolchain_path) -def shared_target_dir(): - return (Path(__file__).parent / "../../../../build/tmp/cargo-target").resolve() - - -def cargo_env(): - return dict(os.environ, CARGO_TARGET_DIR=str(shared_target_dir())) +def get_temp_dir(): + shm = Path("/dev/shm") + if shm.exists() and os.access(shm, os.W_OK): + return shm / "cpp2rust-tests" + return Path("/tmp/cpp2rust-tests") def is_multi_file_test(p):