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)),);
+ }
+}