diff --git a/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs b/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs index 28fef3d8e..ec0f78760 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs @@ -318,7 +318,7 @@ impl<'tcx> OptionApiGenerator<'_, 'tcx> { } __NEWLINE__ inline rs_std::Option<#arg_ty>& rs_std::Option<#arg_ty>::operator=(#arg_ty&& value) noexcept { if (tag() != #none_val) { - *#some_ptr_val = ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct(#some_ptr_val, ::std::move(value)); } else { #write_some_to_tag ::std::construct_at(#some_ptr_val, ::std::move(value)); @@ -358,6 +358,7 @@ impl<'tcx> OptionApiGenerator<'_, 'tcx> { let mut prereqs = CcPrerequisites::default(); // For std::move. prereqs.includes.insert(CcInclude::utility()); + prereqs.includes.insert(self.db.support_header("internal/move_assign.h")); let tag_method_cc_details = tag_method.cc_details.into_tokens(&mut prereqs); let cc_details = CcSnippet { tokens: quote! { @@ -555,7 +556,7 @@ impl<'tcx> ResultApiGenerator<'_, 'tcx> { ::std::construct_at(#ok_ptr, ::std::move(ok)); } else { #write_ok_to_tag - *#ok_ptr = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct(#ok_ptr, ::std::move(ok)); } return *this; } __NEWLINE__ @@ -595,7 +596,7 @@ impl<'tcx> ResultApiGenerator<'_, 'tcx> { ::std::construct_at(#err_ptr, ::std::move(err.error())); } else { #write_err_to_tag - *#err_ptr = ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct(#err_ptr, ::std::move(err.error())); } return *this; } __NEWLINE__ @@ -662,6 +663,7 @@ impl<'tcx> ResultApiGenerator<'_, 'tcx> { let mut prereqs = CcPrerequisites::default(); prereqs.includes.insert(CcInclude::utility()); prereqs.includes.insert(db.support_header("internal/check.h")); + prereqs.includes.insert(db.support_header("internal/move_assign.h")); prereqs.includes.insert(CcInclude::cstring()); let move_construct_ok_details = move_constructor_ok.cc_details.into_tokens(&mut prereqs); let move_construct_err_details = move_constructor_err.cc_details.into_tokens(&mut prereqs); diff --git a/cc_bindings_from_rs/test/enums/option_cc_api.h b/cc_bindings_from_rs/test/enums/option_cc_api.h index 33574bbde..3a75245db 100644 --- a/cc_bindings_from_rs/test/enums/option_cc_api.h +++ b/cc_bindings_from_rs/test/enums/option_cc_api.h @@ -17,6 +17,7 @@ #include "support/annotations_internal.h" #include "support/bridge.h" #include "support/internal/memswap.h" +#include "support/internal/move_assign.h" #include "support/internal/slot.h" #include "support/lifetime_annotations.h" #include "support/rs_std/option.h" @@ -1396,8 +1397,9 @@ inline rs_std::Option<::option::CloneNoDefault>& rs_std::Option<::option::CloneNoDefault>::operator=( ::option::CloneNoDefault&& value) noexcept { if (tag() != 0) { - *reinterpret_cast<::option::CloneNoDefault*>(storage_ + 1) = - ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::option::CloneNoDefault*>(storage_ + 1), + ::std::move(value)); } else { set_tag(1); ::std::construct_at( @@ -1521,8 +1523,9 @@ inline rs_std::Option<::option::CopyNoDefault>& rs_std::Option<::option::CopyNoDefault>::operator=( ::option::CopyNoDefault&& value) noexcept { if (tag() != 0) { - *reinterpret_cast<::option::CopyNoDefault*>(storage_ + 1) = - ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::option::CopyNoDefault*>(storage_ + 1), + ::std::move(value)); } else { set_tag(1); ::std::construct_at( @@ -1642,7 +1645,8 @@ inline rs_std::Option<::option::HasDefault>::Option( inline rs_std::Option<::option::HasDefault>& rs_std::Option< ::option::HasDefault>::operator=(::option::HasDefault&& value) noexcept { if (tag() != UINT64_C(9223372036854775808)) { - *reinterpret_cast<::option::HasDefault*>(storage_) = ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::option::HasDefault*>(storage_), ::std::move(value)); } else { ::std::construct_at(reinterpret_cast<::option::HasDefault*>(storage_), ::std::move(value)); @@ -1860,7 +1864,8 @@ inline rs_std::Option<::option::HasOptions>::Option( inline rs_std::Option<::option::HasOptions>& rs_std::Option< ::option::HasOptions>::operator=(::option::HasOptions&& value) noexcept { if (tag() != 2) { - *reinterpret_cast<::option::HasOptions*>(storage_) = ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::option::HasOptions*>(storage_), ::std::move(value)); } else { ::std::construct_at(reinterpret_cast<::option::HasOptions*>(storage_), ::std::move(value)); @@ -1969,7 +1974,8 @@ inline rs_std::Option<::option::NonMaxU8>::Option( inline rs_std::Option<::option::NonMaxU8>& rs_std::Option< ::option::NonMaxU8>::operator=(::option::NonMaxU8&& value) noexcept { if (tag() != 251) { - *reinterpret_cast<::option::NonMaxU8*>(storage_) = ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::option::NonMaxU8*>(storage_), ::std::move(value)); } else { ::std::construct_at(reinterpret_cast<::option::NonMaxU8*>(storage_), ::std::move(value)); @@ -2082,8 +2088,9 @@ inline rs_std::Option>& rs_std::Option>::operator=( rs_std::Option<::option::NonMaxU8>&& value) noexcept { if (tag() != 252) { - *reinterpret_cast*>(storage_) = - ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast*>(storage_), + ::std::move(value)); } else { ::std::construct_at( reinterpret_cast*>(storage_), @@ -2201,7 +2208,8 @@ inline rs_std::Option<::std::uint8_t>::Option(::std::uint8_t&& value) noexcept { inline rs_std::Option<::std::uint8_t>& rs_std::Option<::std::uint8_t>::operator=(::std::uint8_t&& value) noexcept { if (tag() != 0) { - *reinterpret_cast<::std::uint8_t*>(storage_ + 1) = ::std::move(value); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(storage_ + 1), ::std::move(value)); } else { set_tag(1); ::std::construct_at(reinterpret_cast<::std::uint8_t*>(storage_ + 1), diff --git a/cc_bindings_from_rs/test/enums/result_cc_api.h b/cc_bindings_from_rs/test/enums/result_cc_api.h index 94e8ebc0a..ed4750409 100644 --- a/cc_bindings_from_rs/test/enums/result_cc_api.h +++ b/cc_bindings_from_rs/test/enums/result_cc_api.h @@ -17,6 +17,7 @@ #include "support/annotations_internal.h" #include "support/internal/check.h" #include "support/internal/memswap.h" +#include "support/internal/move_assign.h" #include "support/internal/slot.h" #include "support/lifetime_annotations.h" #include "support/rs_std/result.h" @@ -1450,8 +1451,9 @@ rs_std::Result<::result::CloneNoDefault, ::std::uint8_t>::operator=( ::std::move(ok)); } else { set_tag(0); - *reinterpret_cast<::result::CloneNoDefault*>(__storage + 1) = - ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::result::CloneNoDefault*>(__storage + 1), + ::std::move(ok)); } return *this; } @@ -1472,8 +1474,9 @@ rs_std::Result<::result::CloneNoDefault, ::std::uint8_t>::operator=( ::std::move(err.error())); } else { set_tag(1); - *reinterpret_cast<::std::uint8_t*>(__storage + 1) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 1), + ::std::move(err.error())); } return *this; } @@ -1575,8 +1578,9 @@ rs_std::Result<::result::CopyNoDefault, ::std::uint8_t>::operator=( ::std::move(ok)); } else { set_tag(0); - *reinterpret_cast<::result::CopyNoDefault*>(__storage + 1) = - ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::result::CopyNoDefault*>(__storage + 1), + ::std::move(ok)); } return *this; } @@ -1597,8 +1601,9 @@ rs_std::Result<::result::CopyNoDefault, ::std::uint8_t>::operator=( ::std::move(err.error())); } else { set_tag(1); - *reinterpret_cast<::std::uint8_t*>(__storage + 1) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 1), + ::std::move(err.error())); } return *this; } @@ -1688,7 +1693,8 @@ rs_std::Result<::result::HasDefault, ::std::uint8_t>::operator=( ::std::construct_at(reinterpret_cast<::result::HasDefault*>(__storage), ::std::move(ok)); } else { - *reinterpret_cast<::result::HasDefault*>(__storage) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::result::HasDefault*>(__storage), ::std::move(ok)); } return *this; } @@ -1709,8 +1715,9 @@ rs_std::Result<::result::HasDefault, ::std::uint8_t>::operator=( ::std::move(err.error())); } else { set_tag(UINT64_C(9223372036854775808)); - *reinterpret_cast<::std::uint8_t*>(__storage + 8) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 8), + ::std::move(err.error())); } return *this; } @@ -1808,8 +1815,9 @@ rs_std::Result<::result::HasNoDefault, ::std::uint8_t>::operator=( ::std::move(err.error())); } else { set_tag(UINT64_C(9223372036854775808)); - *reinterpret_cast<::std::uint8_t*>(__storage + 8) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 8), + ::std::move(err.error())); } return *this; } @@ -1922,8 +1930,10 @@ operator=(rs_std::Result<::std::uint32_t, ::std::uint32_t>&& ok) noexcept { __storage), ::std::move(ok)); } else { - *reinterpret_cast*>( - __storage) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast*>( + __storage), + ::std::move(ok)); } return *this; } @@ -1947,8 +1957,9 @@ rs_std::Result, ::std::move(err.error())); } else { set_tag(2); - *reinterpret_cast<::std::uint32_t*>(__storage + 4) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint32_t*>(__storage + 4), + ::std::move(err.error())); } return *this; } @@ -2070,7 +2081,8 @@ operator=(::std::uint32_t&& ok) noexcept { ::std::move(ok)); } else { set_tag(2); - *reinterpret_cast<::std::uint32_t*>(__storage + 4) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint32_t*>(__storage + 4), ::std::move(ok)); } return *this; } @@ -2098,8 +2110,10 @@ operator=(rs_std::unexpected>&& __storage), ::std::move(err.error())); } else { - *reinterpret_cast*>( - __storage) = ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast*>( + __storage), + ::std::move(err.error())); } return *this; } @@ -2234,7 +2248,8 @@ rs_std::Result<::std::uint8_t, ::result::CloneNoDefault>::operator=( ::std::move(ok)); } else { set_tag(0); - *reinterpret_cast<::std::uint8_t*>(__storage + 1) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 1), ::std::move(ok)); } return *this; } @@ -2257,8 +2272,9 @@ rs_std::Result<::std::uint8_t, ::result::CloneNoDefault>::operator=( ::std::move(err.error())); } else { set_tag(1); - *reinterpret_cast<::result::CloneNoDefault*>(__storage + 1) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::result::CloneNoDefault*>(__storage + 1), + ::std::move(err.error())); } return *this; } @@ -2360,7 +2376,8 @@ rs_std::Result<::std::uint8_t, ::result::CopyNoDefault>::operator=( ::std::move(ok)); } else { set_tag(0); - *reinterpret_cast<::std::uint8_t*>(__storage + 1) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 1), ::std::move(ok)); } return *this; } @@ -2382,8 +2399,9 @@ rs_std::Result<::std::uint8_t, ::result::CopyNoDefault>::operator=( ::std::move(err.error())); } else { set_tag(1); - *reinterpret_cast<::result::CopyNoDefault*>(__storage + 1) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::result::CopyNoDefault*>(__storage + 1), + ::std::move(err.error())); } return *this; } @@ -2476,7 +2494,8 @@ rs_std::Result<::std::uint8_t, ::result::HasDefault>::operator=( ::std::move(ok)); } else { set_tag(UINT64_C(9223372036854775808)); - *reinterpret_cast<::std::uint8_t*>(__storage + 8) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 8), ::std::move(ok)); } return *this; } @@ -2494,8 +2513,9 @@ rs_std::Result<::std::uint8_t, ::result::HasDefault>::operator=( ::std::construct_at(reinterpret_cast<::result::HasDefault*>(__storage), ::std::move(err.error())); } else { - *reinterpret_cast<::result::HasDefault*>(__storage) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::result::HasDefault*>(__storage), + ::std::move(err.error())); } return *this; } @@ -2592,7 +2612,8 @@ rs_std::Result<::std::uint8_t, ::result::HasNoDefault>::operator=( ::std::move(ok)); } else { set_tag(UINT64_C(9223372036854775808)); - *reinterpret_cast<::std::uint8_t*>(__storage + 8) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 8), ::std::move(ok)); } return *this; } @@ -2697,7 +2718,8 @@ rs_std::Result<::std::uint32_t, ::std::uint32_t>::operator=( ::std::move(ok)); } else { set_tag(0); - *reinterpret_cast<::std::uint32_t*>(__storage + 4) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint32_t*>(__storage + 4), ::std::move(ok)); } return *this; } @@ -2718,8 +2740,9 @@ rs_std::Result<::std::uint32_t, ::std::uint32_t>::operator=( ::std::move(err.error())); } else { set_tag(1); - *reinterpret_cast<::std::uint32_t*>(__storage + 4) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint32_t*>(__storage + 4), + ::std::move(err.error())); } return *this; } @@ -2816,7 +2839,8 @@ inline rs_std::Result<::std::uint8_t, ::std::uint8_t>& rs_std::Result< ::std::move(ok)); } else { set_tag(0); - *reinterpret_cast<::std::uint8_t*>(__storage + 1) = ::std::move(ok); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 1), ::std::move(ok)); } return *this; } @@ -2837,8 +2861,9 @@ rs_std::Result<::std::uint8_t, ::std::uint8_t>::operator=( ::std::move(err.error())); } else { set_tag(1); - *reinterpret_cast<::std::uint8_t*>(__storage + 1) = - ::std::move(err.error()); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 1), + ::std::move(err.error())); } return *this; } diff --git a/cc_bindings_from_rs/test/structs/const_field/BUILD b/cc_bindings_from_rs/test/structs/const_field/BUILD new file mode 100644 index 000000000..d0d5a34c1 --- /dev/null +++ b/cc_bindings_from_rs/test/structs/const_field/BUILD @@ -0,0 +1,62 @@ +load( + "@rules_cc//cc:cc_library.bzl", + "cc_library", +) +load( + "@rules_rust//rust:defs.bzl", + "rust_library", +) +load( + "//cc_bindings_from_rs/bazel_support:cc_bindings_from_rust_rule.bzl", + "cc_bindings_from_rust", +) +load( + "//cc_bindings_from_rs/test/golden:golden_test.bzl", + "golden_test", +) +load( + "//common:crubit_wrapper_macros_oss.bzl", + "crubit_cc_test", +) + +package(default_applicable_licenses = ["//:license"]) + +cc_library( + name = "cc_struct", + hdrs = ["cc_struct.h"], + aspect_hints = ["//features:supported"], +) + +rust_library( + name = "const_field", + testonly = 1, + srcs = ["lib.rs"], + cc_deps = [":cc_struct"], + proc_macro_deps = [ + "//support:crubit_annotate", + ], +) + +cc_bindings_from_rust( + name = "lib_cc_api", + testonly = 1, + crate = ":const_field", +) + +golden_test( + name = "golden_test", + basename = "const_field", + golden_h = "const_field_cc_api.h", + golden_rs = "const_field_cc_api_impl.rs", + rust_library = "const_field", +) + +crubit_cc_test( + name = "test", + srcs = ["test.cc"], + deps = [ + ":cc_struct", + ":lib_cc_api", + "//testing/base/public:gunit_main", + ], +) diff --git a/cc_bindings_from_rs/test/structs/const_field/cc_struct.h b/cc_bindings_from_rs/test/structs/const_field/cc_struct.h new file mode 100644 index 000000000..2591ec377 --- /dev/null +++ b/cc_bindings_from_rs/test/structs/const_field/cc_struct.h @@ -0,0 +1,14 @@ +// 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 THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_CONST_FIELD_CC_STRUCT_H_ +#define THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_CONST_FIELD_CC_STRUCT_H_ + +#include + +struct struct_with_const_field { + const size_t num_page_locations; +}; + +#endif // THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_CONST_FIELD_CC_STRUCT_H_ diff --git a/cc_bindings_from_rs/test/structs/const_field/const_field_cc_api.h b/cc_bindings_from_rs/test/structs/const_field/const_field_cc_api.h new file mode 100644 index 000000000..a75908908 --- /dev/null +++ b/cc_bindings_from_rs/test/structs/const_field/const_field_cc_api.h @@ -0,0 +1,261 @@ +// 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 + +// Automatically @generated C++ bindings for the following Rust crate: +// const_field_golden +// Features: fmt, supported, types + +// clang-format off +#ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_CONST_FIELD_CONST_FIELD_GOLDEN +#define THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_CONST_FIELD_CONST_FIELD_GOLDEN + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +#pragma clang diagnostic ignored "-Wunused-private-field" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#include "support/bridge.h" +#include "support/internal/check.h" +#include "support/internal/move_assign.h" +#include "support/internal/slot.h" +#include "support/rs_std/result.h" + +#include +#include +#include +#include +#include + +#include "cc_bindings_from_rs/test/structs/const_field/cc_struct.h" + +namespace const_field { + +// CRUBIT_ANNOTATE: must_bind= +// +// Generated from: +// cc_bindings_from_rs/test/structs/const_field/lib.rs;l=13 +::std::optional<::struct_with_const_field> +return_struct_with_const_field_by_value_in_option(); + +} // namespace const_field + +#ifndef _CRUBIT_BINDINGS_FOR_rs_ustd_x00000020_x0000003a_x0000003a_x00000020Result_x00000020_x0000003c_x00000020_x0000003a_x0000003a_x00000020struct_uwith_uconst_ufield_x00000020_x0000002c_x00000020_x0000003a_x0000003a_x00000020std_x00000020_x0000003a_x0000003a_x00000020uint8_ut_x00000020_x0000003e +#define _CRUBIT_BINDINGS_FOR_rs_ustd_x00000020_x0000003a_x0000003a_x00000020Result_x00000020_x0000003c_x00000020_x0000003a_x0000003a_x00000020struct_uwith_uconst_ufield_x00000020_x0000002c_x00000020_x0000003a_x0000003a_x00000020std_x00000020_x0000003a_x0000003a_x00000020uint8_ut_x00000020_x0000003e +template <> +struct alignas(8) CRUBIT_INTERNAL_RUST_TYPE( + "std :: result :: Result < :: cc_struct :: struct_with_const_field , u8 >") + rs_std::Result<::struct_with_const_field, ::std::uint8_t> { + public: + // Rust types that are `Copy` get trivial, `default` C++ copy constructor and + // assignment operator. + Result(const Result&) = default; + Result& operator=(const Result&) = default; + Result(Result&&) = default; + Result& operator=(Result&&) = default; + + Result(::crubit::UnsafeRelocateTag, Result&& value) { + ::std::memcpy(this, &value, sizeof(value)); + } + Result(::struct_with_const_field&& ok) noexcept; + Result& operator=(::struct_with_const_field&& ok) noexcept; + Result(rs_std::unexpected<::std::uint8_t>&& err) noexcept; + Result& operator=(rs_std::unexpected<::std::uint8_t>&& err) noexcept; + template + Result(::std::in_place_t, Args&&... args); + template + Result(rs_std::unexpect_t, Args&&... args); + explicit constexpr operator bool() const noexcept; + constexpr bool has_value() const noexcept; + ::struct_with_const_field& value() &; + ::struct_with_const_field&& value() &&; + ::std::uint8_t& err() &; + ::std::uint8_t&& err() &&; + ~Result() noexcept = default; + + private: + constexpr ::std::uint8_t tag() const& noexcept; + void set_tag(::std::uint8_t tag) noexcept; + void check_has_ok(); + void check_has_err(); + + private: + unsigned char __storage[16]; +}; +#endif + +namespace const_field { + +// CRUBIT_ANNOTATE: must_bind= +// +// Generated from: +// cc_bindings_from_rs/test/structs/const_field/lib.rs;l=7 +rs_std::Result<::struct_with_const_field, ::std::uint8_t> +return_struct_with_const_field_by_value_in_result(); + +namespace __crubit_internal { +extern "C" void +__crubit_thunk_return_ustruct_uwith_uconst_ufield_uby_uvalue_uin_uoption( + unsigned char* __ret_ptr); +} +inline ::std::optional<::struct_with_const_field> +return_struct_with_const_field_by_value_in_option() { + unsigned char __return_value_storage[::crubit::OptionAbi< + ::crubit::TransmuteAbi>::kSize]; + __crubit_internal:: + __crubit_thunk_return_ustruct_uwith_uconst_ufield_uby_uvalue_uin_uoption( + __return_value_storage); + return ::crubit::internal::Decode< + ::crubit::OptionAbi<::crubit::TransmuteAbi>>( + ::crubit::OptionAbi<::crubit::TransmuteAbi>( + ::crubit::TransmuteAbi()), + __return_value_storage); +} + +namespace __crubit_internal { +extern "C" void +__crubit_thunk_return_ustruct_uwith_uconst_ufield_uby_uvalue_uin_uresult( + rs_std::Result<::struct_with_const_field, ::std::uint8_t>* __ret_ptr); +} +inline rs_std::Result<::struct_with_const_field, ::std::uint8_t> +return_struct_with_const_field_by_value_in_result() { + crubit::Slot> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal:: + __crubit_thunk_return_ustruct_uwith_uconst_ufield_uby_uvalue_uin_uresult( + __return_value_storage); + return ::std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +} // namespace const_field + +#ifndef _CRUBIT_BINDINGS_FOR_IMPL_rs_ustd_x00000020_x0000003a_x0000003a_x00000020Result_x00000020_x0000003c_x00000020_x0000003a_x0000003a_x00000020struct_uwith_uconst_ufield_x00000020_x0000002c_x00000020_x0000003a_x0000003a_x00000020std_x00000020_x0000003a_x0000003a_x00000020uint8_ut_x00000020_x0000003e +#define _CRUBIT_BINDINGS_FOR_IMPL_rs_ustd_x00000020_x0000003a_x0000003a_x00000020Result_x00000020_x0000003c_x00000020_x0000003a_x0000003a_x00000020struct_uwith_uconst_ufield_x00000020_x0000002c_x00000020_x0000003a_x0000003a_x00000020std_x00000020_x0000003a_x0000003a_x00000020uint8_ut_x00000020_x0000003e +static_assert(::std::is_trivially_copy_constructible_v< + rs_std::Result<::struct_with_const_field, ::std::uint8_t>>); +static_assert(::std::is_trivially_copy_assignable_v< + rs_std::Result<::struct_with_const_field, ::std::uint8_t>>); +static_assert(::std::is_trivially_move_constructible_v< + rs_std::Result<::struct_with_const_field, ::std::uint8_t>>); +static_assert(::std::is_trivially_move_assignable_v< + rs_std::Result<::struct_with_const_field, ::std::uint8_t>>); +inline rs_std::Result<::struct_with_const_field, ::std::uint8_t>::Result( + ::struct_with_const_field&& ok) noexcept { + set_tag(0); + ::std::construct_at( + reinterpret_cast<::struct_with_const_field*>(__storage + 8), + ::std::move(ok)); +} +inline rs_std::Result<::struct_with_const_field, ::std::uint8_t>& +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::operator=( + ::struct_with_const_field&& ok) noexcept { + if (!has_value()) { + ::std::destroy_at(reinterpret_cast<::std::uint8_t*>(__storage + 1)); + set_tag(0); + ::std::construct_at( + reinterpret_cast<::struct_with_const_field*>(__storage + 8), + ::std::move(ok)); + } else { + set_tag(0); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::struct_with_const_field*>(__storage + 8), + ::std::move(ok)); + } + return *this; +} + +inline rs_std::Result<::struct_with_const_field, ::std::uint8_t>::Result( + rs_std::unexpected<::std::uint8_t>&& err) noexcept { + set_tag(1); + ::std::construct_at(reinterpret_cast<::std::uint8_t*>(__storage + 1), + ::std::move(err.error())); +} +inline rs_std::Result<::struct_with_const_field, ::std::uint8_t>& +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::operator=( + rs_std::unexpected<::std::uint8_t>&& err) noexcept { + if (has_value()) { + ::std::destroy_at(__storage + 8); + set_tag(1); + ::std::construct_at(reinterpret_cast<::std::uint8_t*>(__storage + 1), + ::std::move(err.error())); + } else { + set_tag(1); + ::crubit::MoveAssignOrDestroyAndConstruct( + reinterpret_cast<::std::uint8_t*>(__storage + 1), + ::std::move(err.error())); + } + return *this; +} + +template +inline rs_std::Result<::struct_with_const_field, ::std::uint8_t>::Result( + std::in_place_t, Args&&... args) { + set_tag(0); + std::construct_at(__storage + 8, std::forward(args)...); +} +template +inline rs_std::Result<::struct_with_const_field, ::std::uint8_t>::Result( + rs_std::unexpect_t, Args&&... args) { + set_tag(1); + std::construct_at(__storage + 1, std::forward(args)...); +} +inline constexpr rs_std::Result<::struct_with_const_field, ::std::uint8_t>:: +operator bool() const noexcept { + return has_value(); +} +inline constexpr bool rs_std::Result< + ::struct_with_const_field, ::std::uint8_t>::has_value() const noexcept { + return tag() == 0; +} +inline ::struct_with_const_field& +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::value() & { + check_has_ok(); + return *reinterpret_cast<::struct_with_const_field*>(__storage + 8); +} +inline ::struct_with_const_field&& +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::value() && { + check_has_ok(); + return ::std::move( + *reinterpret_cast<::struct_with_const_field*>(__storage + 8)); +} +inline ::std::uint8_t& +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::err() & { + check_has_err(); + return *reinterpret_cast<::std::uint8_t*>(__storage + 1); +} +inline ::std::uint8_t&& +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::err() && { + check_has_err(); + return ::std::move(*reinterpret_cast<::std::uint8_t*>(__storage + 1)); +} +static_assert(::std::is_trivially_destructible_v< + rs_std::Result<::struct_with_const_field, ::std::uint8_t>>); +inline constexpr ::std::uint8_t rs_std::Result< + ::struct_with_const_field, ::std::uint8_t>::tag() const& noexcept { + std::array __bytes = {}; + for (std::size_t i = 0; i < sizeof(::std::uint8_t); ++i) { + __bytes[i] = __storage[0 + i]; + } + return std::bit_cast<::std::uint8_t>(__bytes); +} +inline void rs_std::Result<::struct_with_const_field, ::std::uint8_t>::set_tag( + ::std::uint8_t tag) noexcept { + auto __bytes = + std::bit_cast>(tag); + for (std::size_t i = 0; i < sizeof(::std::uint8_t); ++i) { + __storage[0 + i] = __bytes[i]; + } +} + +inline void +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::check_has_ok() { + CHECK(has_value()) << "Bad value access on rs_std::Result"; +} +inline void +rs_std::Result<::struct_with_const_field, ::std::uint8_t>::check_has_err() { + CHECK(!has_value()) << "Bad error access on rs_std::Result"; +} +#endif + +#pragma clang diagnostic pop +#endif // THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_CONST_FIELD_CONST_FIELD_GOLDEN diff --git a/cc_bindings_from_rs/test/structs/const_field/const_field_cc_api_impl.rs b/cc_bindings_from_rs/test/structs/const_field/const_field_cc_api_impl.rs new file mode 100644 index 000000000..879083dbe --- /dev/null +++ b/cc_bindings_from_rs/test/structs/const_field/const_field_cc_api_impl.rs @@ -0,0 +1,43 @@ +// 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 + +// Automatically @generated C++ bindings for the following Rust crate: +// const_field_golden +// Features: fmt, supported, types + +#![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] +#![allow(improper_ctypes_definitions)] +#![deny(warnings)] + +extern crate alloc; +extern crate core; +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_return_ustruct_uwith_uconst_ufield_uby_uvalue_uin_uoption( + __ret_ptr: *mut core::ffi::c_uchar, +) -> () { + unsafe { + let __rs_return_value = + ::const_field_golden::return_struct_with_const_field_by_value_in_option(); + unsafe { + ::bridge_rust::internal::encode( + ::bridge_rust::OptionAbi(::bridge_rust::transmute_abi::< + ::cc_struct::struct_with_const_field, + >()), + __ret_ptr as *mut core::ffi::c_uchar, + __rs_return_value, + ); + } + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_return_ustruct_uwith_uconst_ufield_uby_uvalue_uin_uresult( + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value = + ::const_field_golden::return_struct_with_const_field_by_value_in_result(); + (__ret_ptr as *mut ::core::result::Result<::cc_struct::struct_with_const_field, u8>) + .write(__rs_return_value); + } +} diff --git a/cc_bindings_from_rs/test/structs/const_field/lib.rs b/cc_bindings_from_rs/test/structs/const_field/lib.rs new file mode 100644 index 000000000..c49984928 --- /dev/null +++ b/cc_bindings_from_rs/test/structs/const_field/lib.rs @@ -0,0 +1,16 @@ +// 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 + +// Regression test for b/504720727 +#[crubit_annotate::must_bind] +pub fn return_struct_with_const_field_by_value_in_result( +) -> Result { + Ok(cc_struct::struct_with_const_field { num_page_locations: 42 }) +} + +#[crubit_annotate::must_bind] +pub fn return_struct_with_const_field_by_value_in_option( +) -> Option { + Some(cc_struct::struct_with_const_field { num_page_locations: 42 }) +} diff --git a/cc_bindings_from_rs/test/structs/const_field/test.cc b/cc_bindings_from_rs/test/structs/const_field/test.cc new file mode 100644 index 000000000..8ece37455 --- /dev/null +++ b/cc_bindings_from_rs/test/structs/const_field/test.cc @@ -0,0 +1,19 @@ +// 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 "gtest/gtest.h" +#include "cc_bindings_from_rs/test/structs/const_field/const_field.h" + +namespace { + +TEST(ConstFieldTest, StructWithConstFieldCanBeReturnedByValueInsideGenerics) { + auto result = + const_field::return_struct_with_const_field_by_value_in_result(); + EXPECT_TRUE(result.has_value()); + auto option = + const_field::return_struct_with_const_field_by_value_in_option(); + EXPECT_TRUE(option.has_value()); +} + +} // namespace diff --git a/support/internal/BUILD b/support/internal/BUILD index f776dc0e1..4a560b9b1 100644 --- a/support/internal/BUILD +++ b/support/internal/BUILD @@ -14,6 +14,7 @@ cc_library( "fmt.h", "lazy_init.h", "memswap.h", + "move_assign.h", "offsetof.h", "sizeof.h", "slot.h", diff --git a/support/internal/BUILD.gn b/support/internal/BUILD.gn index 9850eddd3..61b6681d0 100644 --- a/support/internal/BUILD.gn +++ b/support/internal/BUILD.gn @@ -24,6 +24,7 @@ source_set("bindings_support") { "fmt.h", "lazy_init.h", "memswap.h", + "move_assign.h", "offsetof.h", "sizeof.h", "slot.h", diff --git a/support/internal/CMakeLists.txt b/support/internal/CMakeLists.txt index d9a86634f..1a1b0e6a9 100644 --- a/support/internal/CMakeLists.txt +++ b/support/internal/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(crubit_support_internal_bindings_support STATIC "fmt.h" "lazy_init.h" "memswap.h" +"move_assign.h" "offsetof.h" "sizeof.h" "slot.h" diff --git a/support/internal/move_assign.h b/support/internal/move_assign.h new file mode 100644 index 000000000..862de541c --- /dev/null +++ b/support/internal/move_assign.h @@ -0,0 +1,26 @@ +// 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 THIRD_PARTY_CRUBIT_SUPPORT_INTERNAL_MOVE_ASSIGN_H_ +#define THIRD_PARTY_CRUBIT_SUPPORT_INTERNAL_MOVE_ASSIGN_H_ + +#include +#include +#include + +namespace crubit { + +template +inline void MoveAssignOrDestroyAndConstruct(T* ptr, U&& value) { + if constexpr (std::is_move_assignable_v) { + *ptr = std::forward(value); + } else { + std::destroy_at(ptr); + std::construct_at(ptr, std::forward(value)); + } +} + +} // namespace crubit + +#endif // THIRD_PARTY_CRUBIT_SUPPORT_INTERNAL_MOVE_ASSIGN_H_