Add tests for simple functions without lifetime annotations PiperOrigin-RevId: 650164783 Change-Id: I63b8a5c498d925d56fd6fba84dfa87ecb3c8a5dd
diff --git a/bazel/llvm.bzl b/bazel/llvm.bzl index 962a650..c088b91 100644 --- a/bazel/llvm.bzl +++ b/bazel/llvm.bzl
@@ -53,7 +53,7 @@ executable = False, ) -LLVM_COMMIT_SHA = "7102eae4c0640492e1fcea3da7f22f4e75a4f062" +LLVM_COMMIT_SHA = "de88b2cb16af4bba659d0bb2ddf10bda681ec84d" def llvm_loader_repository_dependencies(): # This *declares* the dependency, but it won't actually be *downloaded* unless it's used.
diff --git a/rs_bindings_from_cc/test/function/non_extern_c/BUILD b/rs_bindings_from_cc/test/function/non_extern_c/BUILD new file mode 100644 index 0000000..e707490 --- /dev/null +++ b/rs_bindings_from_cc/test/function/non_extern_c/BUILD
@@ -0,0 +1,18 @@ +"""End-to-end example of using simple functions.""" + +load("//common:crubit_wrapper_macros_oss.bzl", "crubit_rust_test") +load("//rs_bindings_from_cc/test:test_bindings.bzl", "crubit_test_cc_library") + +package(default_applicable_licenses = ["//:license"]) + +crubit_test_cc_library( + name = "simple_functions", + srcs = ["simple_functions.cc"], + hdrs = ["simple_functions.h"], +) + +crubit_rust_test( + name = "main", + srcs = ["test.rs"], + cc_deps = [":simple_functions"], +)
diff --git a/rs_bindings_from_cc/test/function/non_extern_c/simple_functions.cc b/rs_bindings_from_cc/test/function/non_extern_c/simple_functions.cc new file mode 100644 index 0000000..43333cd --- /dev/null +++ b/rs_bindings_from_cc/test/function/non_extern_c/simple_functions.cc
@@ -0,0 +1,40 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "rs_bindings_from_cc/test/function/non_extern_c/simple_functions.h" + +int return_value() { return 42; } + +int* return_pointer() { + static int i = 42; + return &i; +} + +int& return_reference() { + static int i = 42; + return i; +} + +void take_pointer(int* i) { + if (i) { + *i = 42; + } +} + +void take_reference(int& i) { i = 42; } + +const int* forward_pointer(const int* i) { return i; } + +const int& forward_reference(const int& i) { return i; } + +int multiply(int x, int y) { return x * y; } + +int multiply_with_unnamed_parameters(int x, int y) { return x * y; } + +int multiply_with_keyword_named_parameters(int self, int crate, int super) { + return self * crate * super; +} + +int (*get_pointer_to_multiply_function())(int, int) { return multiply; } +int (&get_reference_to_multiply_function())(int, int) { return multiply; }
diff --git a/rs_bindings_from_cc/test/function/non_extern_c/simple_functions.h b/rs_bindings_from_cc/test/function/non_extern_c/simple_functions.h new file mode 100644 index 0000000..ce35a0f --- /dev/null +++ b/rs_bindings_from_cc/test/function/non_extern_c/simple_functions.h
@@ -0,0 +1,41 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CRUBIT_RS_BINDINGS_FROM_CC_TEST_FUNCTION_SIMPLE_SIMPLE_FUNCTIONS_H_ +#define CRUBIT_RS_BINDINGS_FROM_CC_TEST_FUNCTION_SIMPLE_SIMPLE_FUNCTIONS_H_ + +int return_value(); +int* return_pointer(); +int& return_reference(); +void take_pointer(int* i); +void take_reference(int& i); +const int* forward_pointer(const int* i); +const int& forward_reference(const int& i); +int multiply(int x, int y); +int multiply_with_unnamed_parameters(int, int); +int multiply_with_keyword_named_parameters(int self, int crate, int super); + +// https://cdecl.org/?q=int+%28*get_multiply_function%28%29%29%28int%2C+int%29: +// declare foo as function returning pointer to function (int, int) returning +// int +int (*get_pointer_to_multiply_function())(int, int); + +// Same as above, but returning a *reference* to a function. +int (&get_reference_to_multiply_function())(int, int); + +inline int (*inline_get_pointer_to_multiply_function())(int, int) { + return multiply; +} + +inline int apply_binary_op(int x, int y, int (*op)(int, int)) { + return op(x, y); +} + +// TODO(b/217419782): Add testcases for pointers to functions that take or +// return takes/returns non-trivially-movable types by value. In particular, +// some function signatures might require going through a C++ thunk - such +// function pointers can't work without a thunk. See also +// <internal link> + +#endif // CRUBIT_RS_BINDINGS_FROM_CC_TEST_FUNCTION_SIMPLE_SIMPLE_FUNCTIONS_H_
diff --git a/rs_bindings_from_cc/test/function/non_extern_c/test.rs b/rs_bindings_from_cc/test/function/non_extern_c/test.rs new file mode 100644 index 0000000..8f1aebf --- /dev/null +++ b/rs_bindings_from_cc/test/function/non_extern_c/test.rs
@@ -0,0 +1,119 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#[cfg(test)] +mod tests { + #[test] + fn test_return_value() { + use simple_functions::return_value; + assert_eq!(return_value(), 42); + } + + #[test] + fn test_return_pointer() { + use simple_functions::return_pointer; + unsafe { + assert_eq!(*return_pointer(), 42); + } + } + + #[test] + fn test_return_reference() { + use simple_functions::return_reference; + unsafe { + assert_eq!(*return_reference(), 42); + } + } + + #[test] + fn test_take_pointer() { + use simple_functions::take_pointer; + unsafe { + take_pointer(std::ptr::null_mut()); + } + let mut i: i32 = 0; + unsafe { + take_pointer(&mut i); + } + assert_eq!(i, 42); + } + + #[test] + fn test_take_reference() { + use simple_functions::take_reference; + let mut i: i32 = 0; + unsafe { + take_reference(&mut i); + } + assert_eq!(i, 42); + } + + #[test] + fn test_forward_pointer() { + use simple_functions::forward_pointer; + assert_eq!(unsafe { forward_pointer(std::ptr::null()) }, std::ptr::null()); + let i: i32 = 42; + assert_eq!(unsafe { *forward_pointer(&i) }, 42); + } + + #[test] + fn test_forward_reference() { + use simple_functions::forward_reference; + let i: i32 = 42; + assert_eq!(unsafe { *forward_reference(&i) }, 42); + } + + #[test] + fn test_multiply() { + assert_eq!(simple_functions::multiply(42, 123), 42 * 123); + } + + #[test] + fn test_multiply_with_unnamed_parameters() { + assert_eq!(simple_functions::multiply_with_unnamed_parameters(42, 456), 42 * 456); + } + + #[test] + fn test_multiply_with_keyword_named_parameters() { + assert_eq!( + 42 * 123 * 456, + simple_functions::multiply_with_keyword_named_parameters(42, 123, 456) + ); + } + + #[test] + fn test_function_pointer() { + let maybe_mul_fn = simple_functions::get_pointer_to_multiply_function(); + let mul_fn = maybe_mul_fn.expect("Expecting non-null / non-None function pointer"); + assert_eq!(mul_fn(123, 456), 123 * 456); + } + + #[test] + fn test_function_reference() { + // TODO(b/217419782): Replicate `test_function_pointer`, but for C++ + // references. (e.g. no `expect` / `Option` unwrapping should be + // needed). + } + + #[test] + fn test_function_pointer_returned_from_inline_function() { + let maybe_mul_fn = simple_functions::inline_get_pointer_to_multiply_function(); + let mul_fn = maybe_mul_fn.expect("Expecting non-null / non-None function pointer"); + assert_eq!(mul_fn(123, 456), 123 * 456); + } + + /// Test that function pointers can be accepted as function parameters. + #[test] + fn test_apply_binary_op() { + extern "C" fn multiply(x: i32, y: i32) -> i32 { + x * y + } + extern "C" fn add(x: i32, y: i32) -> i32 { + x + y + } + + assert_eq!(100 * 200, simple_functions::apply_binary_op(100, 200, Some(multiply)),); + assert_eq!(300 + 400, simple_functions::apply_binary_op(300, 400, Some(add)),); + } +}