Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 1 | // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| 2 | // Exceptions. See /LICENSE for license information. |
| 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 4 | |
| 5 | // This file defines an intermediate representation (IR) used between Clang AST |
| 6 | // and code generators that generate Rust bindings and C++ bindings |
| 7 | // implementation. |
| 8 | // |
| 9 | // All types in this file own their data. This IR is expected to outlive the |
| 10 | // Clang's AST context, therefore it cannot reference data owned by it. |
| 11 | #ifndef CRUBIT_RS_BINDINGS_FROM_CC_IR_H_ |
| 12 | #define CRUBIT_RS_BINDINGS_FROM_CC_IR_H_ |
| 13 | |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 14 | #include <stdint.h> |
| 15 | |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 16 | #include <iomanip> |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 17 | #include <optional> |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 18 | #include <string> |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 19 | #include <utility> |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 20 | #include <variant> |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 21 | #include <vector> |
| 22 | |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 23 | #include "base/integral_types.h" |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 24 | #include "base/logging.h" |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 25 | #include "rs_bindings_from_cc/bazel_types.h" |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 26 | #include "third_party/absl/strings/string_view.h" |
Marcel Hlopko | 42abfc8 | 2021-08-09 07:03:17 +0000 | [diff] [blame] | 27 | #include "third_party/json/src/json.hpp" |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 28 | #include "util/intops/strong_int.h" |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 29 | |
| 30 | namespace rs_bindings_from_cc { |
| 31 | |
Devin Jeanpierre | 5c87a72 | 2021-09-16 10:35:58 +0000 | [diff] [blame] | 32 | namespace internal { |
| 33 | inline constexpr absl::string_view kRustPtrMut = "*mut"; |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 34 | inline constexpr absl::string_view kRustPtrConst = "*const"; |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 35 | inline constexpr absl::string_view kRustRefMut = "&mut"; |
| 36 | inline constexpr absl::string_view kRustRefConst = "&"; |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 37 | inline constexpr absl::string_view kCcPtr = "*"; |
Googler | 61dce3b | 2021-12-02 09:16:32 +0000 | [diff] [blame] | 38 | inline constexpr absl::string_view kCcLValueRef = "&"; |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 39 | inline constexpr int kJsonIndent = 2; |
Devin Jeanpierre | 5c87a72 | 2021-09-16 10:35:58 +0000 | [diff] [blame] | 40 | } // namespace internal |
| 41 | |
Marcel Hlopko | f1123c8 | 2021-08-19 11:38:52 +0000 | [diff] [blame] | 42 | // A name of a public header of the C++ library. |
| 43 | class HeaderName { |
| 44 | public: |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 45 | explicit HeaderName(std::string name) : name_(std::move(name)) {} |
Marcel Hlopko | f1123c8 | 2021-08-19 11:38:52 +0000 | [diff] [blame] | 46 | |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 47 | absl::string_view IncludePath() const { return name_; } |
Marcel Hlopko | f1123c8 | 2021-08-19 11:38:52 +0000 | [diff] [blame] | 48 | |
| 49 | nlohmann::json ToJson() const; |
| 50 | |
Marcel Hlopko | 7aa38a7 | 2021-11-11 07:39:51 +0000 | [diff] [blame] | 51 | template <typename H> |
| 52 | friend H AbslHashValue(H h, const HeaderName& header_name) { |
| 53 | return H::combine(std::move(h), header_name.name_); |
| 54 | } |
| 55 | |
Marcel Hlopko | f1123c8 | 2021-08-19 11:38:52 +0000 | [diff] [blame] | 56 | private: |
| 57 | // Header pathname in the format suitable for a google3-relative quote |
| 58 | // include. |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 59 | std::string name_; |
Marcel Hlopko | f1123c8 | 2021-08-19 11:38:52 +0000 | [diff] [blame] | 60 | }; |
| 61 | |
Marcel Hlopko | 7aa38a7 | 2021-11-11 07:39:51 +0000 | [diff] [blame] | 62 | inline bool operator==(const HeaderName& lhs, const HeaderName& rhs) { |
| 63 | return lhs.IncludePath() == rhs.IncludePath(); |
| 64 | } |
| 65 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 66 | inline std::ostream& operator<<(std::ostream& o, const HeaderName& h) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 67 | return o << std::setw(internal::kJsonIndent) << h.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 68 | } |
| 69 | |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 70 | // An int uniquely representing a Decl. Since our IR goes through the JSON |
| 71 | // serialization/deserialization at the moment, we need a way to restore graph |
| 72 | // edges that don't follow the JSON tree structure (for example between types |
| 73 | // and records). We use DeclIds for this. |
| 74 | DEFINE_STRONG_INT_TYPE(DeclId, uintptr_t); |
| 75 | |
Googler | 64e4edb | 2021-12-03 12:17:38 +0000 | [diff] [blame] | 76 | // A numerical ID that uniquely identifies a lifetime. |
| 77 | DEFINE_STRONG_INT_TYPE(LifetimeId, int); |
| 78 | |
| 79 | // A lifetime. |
| 80 | struct Lifetime { |
| 81 | nlohmann::json ToJson() const; |
| 82 | |
| 83 | // Lifetime name. Unlike syn::Lifetime, this does not include the apostrophe. |
| 84 | // |
| 85 | // Note that this is not an identifier; the rules for what is a valid lifetime |
| 86 | // name are slightly different than for identifiers, so we simply use a |
| 87 | // std::string instead of an Identifier here. |
| 88 | std::string name; |
| 89 | |
| 90 | LifetimeId id; |
| 91 | }; |
| 92 | |
| 93 | inline std::ostream& operator<<(std::ostream& o, const Lifetime& l) { |
| 94 | return o << std::setw(internal::kJsonIndent) << l.ToJson(); |
| 95 | } |
| 96 | |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 97 | // A C++ type involved in the bindings. It has the knowledge of how the type |
| 98 | // is spelled in C++. |
| 99 | struct CcType { |
Marcel Hlopko | 42abfc8 | 2021-08-09 07:03:17 +0000 | [diff] [blame] | 100 | nlohmann::json ToJson() const; |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 101 | // The name of the type. For example, int or void. |
| 102 | std::string name; |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 103 | |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 104 | // Id of a decl that this type corresponds to. `nullopt` for primitive types. |
| 105 | std::optional<DeclId> decl_id = std::nullopt; |
| 106 | |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 107 | // The C++ const-qualification for the type. |
| 108 | // |
Devin Jeanpierre | c6c62eb | 2021-09-29 07:13:35 +0000 | [diff] [blame] | 109 | // Note: there are two types for which cv-qualification does not do anything: |
| 110 | // references and functions. if `T` is either a function type like `void()`, |
| 111 | // or a reference type like `int&`, then `T`, `const T`, and `volatile T` are |
| 112 | // all the same type in C++. |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 113 | bool is_const = false; |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 114 | |
Googler | ff7fc23 | 2021-12-02 09:43:00 +0000 | [diff] [blame] | 115 | // Type arguments for a generic type. Examples: |
| 116 | // int has no type arguments. |
| 117 | // int* has a single type argument, int. |
| 118 | // tuple<int, float> has two type arguments, int and float. |
| 119 | std::vector<CcType> type_args = {}; |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 120 | }; |
| 121 | |
| 122 | // A Rust type involved in the bindings. It has the knowledge of how the type |
| 123 | // is spelled in Rust. |
| 124 | struct RsType { |
| 125 | nlohmann::json ToJson() const; |
| 126 | |
| 127 | // The name of the type. For example, i32 or (). |
| 128 | std::string name; |
| 129 | |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 130 | // Id of a decl that this type corresponds to. `nullopt` for primitive types. |
| 131 | std::optional<DeclId> decl_id = std::nullopt; |
| 132 | |
Googler | 64e4edb | 2021-12-03 12:17:38 +0000 | [diff] [blame] | 133 | // Lifetime arguments for a generic type. Examples: |
| 134 | // *mut i32 has no lifetime arguments |
| 135 | // &'a 32 has a single lifetime argument, 'a. |
| 136 | // SomeType<'a, 'b> has two lifetime arguments, 'a and 'b. |
| 137 | // Lifetimes are identified by their unique ID. The corresponding Lifetime |
| 138 | // will be found within the lifetime_params of a Func or Record that uses |
| 139 | // this type. |
| 140 | std::vector<LifetimeId> lifetime_args = {}; |
| 141 | |
Googler | ff7fc23 | 2021-12-02 09:43:00 +0000 | [diff] [blame] | 142 | // Type arguments for a generic type. Examples: |
| 143 | // i32 has no type arguments. |
| 144 | // *mut i32 has a single type argument, i32. |
| 145 | // (i32, f32) has two type arguments, i32 and f32. |
| 146 | std::vector<RsType> type_args = {}; |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 147 | }; |
| 148 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 149 | inline std::ostream& operator<<(std::ostream& o, const RsType& type) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 150 | return o << std::setw(internal::kJsonIndent) << type.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 151 | } |
| 152 | |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 153 | // A type involved in the bindings. The rs_type and cc_type will be treated |
| 154 | // as interchangeable during bindings, and so should share the same layout. |
| 155 | // |
| 156 | // For example: a C++ pointer may be a usize in Rust, rather than a pointer, but |
| 157 | // should almost certainly not be a u8, because u8 and pointers are sized and |
| 158 | // aligned differently. |
| 159 | struct MappedType { |
| 160 | static MappedType Void() { return Simple("()", "void"); } |
| 161 | |
| 162 | /// Returns the MappedType for a non-templated/generic, non-cv-qualified type. |
| 163 | /// For example, Void() is Simple("()", "void"). |
| 164 | static MappedType Simple(std::string rs_name, std::string cc_name) { |
| 165 | return MappedType{RsType{rs_name}, CcType{cc_name}}; |
| 166 | } |
| 167 | |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 168 | static MappedType WithDeclIds(std::string rs_name, DeclId rs_decl_id, |
| 169 | std::string cc_name, DeclId cc_decl_id) { |
| 170 | return MappedType{RsType{std::move(rs_name), rs_decl_id}, |
| 171 | CcType{std::move(cc_name), cc_decl_id}}; |
| 172 | } |
| 173 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 174 | static MappedType PointerTo(MappedType pointee_type, |
| 175 | std::optional<LifetimeId> lifetime, |
Googler | 02da3fb | 2021-12-06 11:59:19 +0000 | [diff] [blame^] | 176 | bool nullable = true); |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 177 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 178 | static MappedType LValueReferenceTo(MappedType pointee_type, |
Googler | 02da3fb | 2021-12-06 11:59:19 +0000 | [diff] [blame^] | 179 | std::optional<LifetimeId> lifetime); |
Googler | 61dce3b | 2021-12-02 09:16:32 +0000 | [diff] [blame] | 180 | |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 181 | bool IsVoid() const { return rs_type.name == "()"; } |
| 182 | |
| 183 | nlohmann::json ToJson() const; |
| 184 | |
| 185 | RsType rs_type; |
| 186 | CcType cc_type; |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 187 | }; |
| 188 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 189 | inline std::ostream& operator<<(std::ostream& o, const MappedType& type) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 190 | return o << std::setw(internal::kJsonIndent) << type.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 191 | } |
| 192 | |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 193 | // An identifier involved in bindings. |
| 194 | // |
| 195 | // Examples: |
| 196 | // Identifier of C++'s `int32_t Add(int32_t a, int32_t b)` will be |
| 197 | // `Identifier("add")`. |
| 198 | // |
| 199 | // Invariants: |
| 200 | // `identifier` cannot be empty. |
| 201 | class Identifier { |
| 202 | public: |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 203 | explicit Identifier(std::string identifier) |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 204 | : identifier_(std::move(identifier)) { |
| 205 | CHECK(!identifier_.empty()) << "Identifier name cannot be empty."; |
| 206 | } |
| 207 | |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 208 | absl::string_view Ident() const { return identifier_; } |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 209 | |
Marcel Hlopko | 42abfc8 | 2021-08-09 07:03:17 +0000 | [diff] [blame] | 210 | nlohmann::json ToJson() const; |
| 211 | |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 212 | private: |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 213 | std::string identifier_; |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 214 | }; |
| 215 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 216 | inline std::ostream& operator<<(std::ostream& o, const Identifier& id) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 217 | return o << std::setw(internal::kJsonIndent) << id.Ident(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 218 | } |
| 219 | |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 220 | // A function parameter. |
| 221 | // |
| 222 | // Examples: |
| 223 | // FuncParam of a C++ function `void Foo(int32_t a);` will be |
Devin Jeanpierre | 29a25f1 | 2021-09-15 11:54:32 +0000 | [diff] [blame] | 224 | // `FuncParam{.type=Type{"i32", "int32_t"}, .identifier=Identifier("foo"))`. |
Devin Jeanpierre | 601f14f | 2021-09-15 11:53:18 +0000 | [diff] [blame] | 225 | struct FuncParam { |
Marcel Hlopko | 42abfc8 | 2021-08-09 07:03:17 +0000 | [diff] [blame] | 226 | nlohmann::json ToJson() const; |
| 227 | |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 228 | MappedType type; |
Devin Jeanpierre | 601f14f | 2021-09-15 11:53:18 +0000 | [diff] [blame] | 229 | Identifier identifier; |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 230 | }; |
| 231 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 232 | inline std::ostream& operator<<(std::ostream& o, const FuncParam& param) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 233 | return o << std::setw(internal::kJsonIndent) << param.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 234 | } |
| 235 | |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 236 | enum SpecialName { |
| 237 | kDestructor, |
| 238 | kConstructor, |
| 239 | }; |
| 240 | |
| 241 | std::ostream& operator<<(std::ostream& o, const SpecialName& special_name); |
| 242 | |
| 243 | // A generalized notion of identifier, or an "Unqualified Identifier" in C++ |
| 244 | // jargon: https://en.cppreference.com/w/cpp/language/identifiers |
| 245 | // |
| 246 | // Note that constructors are given a separate variant, so that we can treat |
| 247 | // them differently. After all, they are not invoked or defined like normal |
| 248 | // functions. |
| 249 | using UnqualifiedIdentifier = std::variant<Identifier, SpecialName>; |
| 250 | |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 251 | struct MemberFuncMetadata { |
| 252 | enum ReferenceQualification : char { |
| 253 | kLValue, // void Foo() &; |
| 254 | kRValue, // void Foo() &&; |
| 255 | kUnqualified, // void Foo(); |
| 256 | }; |
| 257 | |
| 258 | struct InstanceMethodMetadata { |
| 259 | ReferenceQualification reference = kUnqualified; |
| 260 | bool is_const = false; |
| 261 | bool is_virtual = false; |
| 262 | }; |
| 263 | |
| 264 | nlohmann::json ToJson() const; |
| 265 | |
| 266 | // The type that this is a member function for. |
Devin Jeanpierre | 7e9a1de | 2021-12-03 08:04:22 +0000 | [diff] [blame] | 267 | DeclId record_id; |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 268 | |
| 269 | // Qualifiers for the instance method. |
| 270 | // |
| 271 | // If null, this is a static method. |
| 272 | std::optional<InstanceMethodMetadata> instance_method_metadata; |
| 273 | }; |
| 274 | |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 275 | // A function involved in the bindings. |
Devin Jeanpierre | 4d33b59 | 2021-09-15 11:53:32 +0000 | [diff] [blame] | 276 | struct Func { |
Marcel Hlopko | 42abfc8 | 2021-08-09 07:03:17 +0000 | [diff] [blame] | 277 | nlohmann::json ToJson() const; |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 278 | |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 279 | UnqualifiedIdentifier name; |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 280 | Label owning_target; |
Michael Forster | 409d941 | 2021-10-07 08:35:29 +0000 | [diff] [blame] | 281 | std::optional<std::string> doc_comment; |
Devin Jeanpierre | 4d33b59 | 2021-09-15 11:53:32 +0000 | [diff] [blame] | 282 | std::string mangled_name; |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 283 | MappedType return_type; |
Devin Jeanpierre | 4d33b59 | 2021-09-15 11:53:32 +0000 | [diff] [blame] | 284 | std::vector<FuncParam> params; |
Googler | 64e4edb | 2021-12-03 12:17:38 +0000 | [diff] [blame] | 285 | std::vector<Lifetime> lifetime_params; |
Devin Jeanpierre | 4d33b59 | 2021-09-15 11:53:32 +0000 | [diff] [blame] | 286 | bool is_inline; |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 287 | // If null, this is not a member function. |
| 288 | std::optional<MemberFuncMetadata> member_func_metadata; |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 289 | }; |
| 290 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 291 | inline std::ostream& operator<<(std::ostream& o, const Func& f) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 292 | return o << std::setw(internal::kJsonIndent) << f.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 293 | } |
| 294 | |
Googler | 2e85f34 | 2021-09-17 07:04:07 +0000 | [diff] [blame] | 295 | // Access specifier for a member or base class. |
| 296 | enum AccessSpecifier { |
| 297 | kPublic, |
| 298 | kProtected, |
| 299 | kPrivate, |
| 300 | }; |
| 301 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 302 | std::ostream& operator<<(std::ostream& o, const AccessSpecifier& access); |
| 303 | |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 304 | // A field (non-static member variable) of a record. |
Michael Forster | 6e95ad3 | 2021-09-15 21:01:21 +0000 | [diff] [blame] | 305 | struct Field { |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 306 | nlohmann::json ToJson() const; |
| 307 | |
Michael Forster | 6e95ad3 | 2021-09-15 21:01:21 +0000 | [diff] [blame] | 308 | Identifier identifier; |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 309 | std::optional<std::string> doc_comment; |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 310 | MappedType type; |
Googler | 2e85f34 | 2021-09-17 07:04:07 +0000 | [diff] [blame] | 311 | AccessSpecifier access; |
Googler | 6986c07 | 2021-09-17 13:54:56 +0000 | [diff] [blame] | 312 | // Field offset in bits. |
| 313 | uint64_t offset; |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 314 | }; |
| 315 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 316 | inline std::ostream& operator<<(std::ostream& o, const Field& f) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 317 | return o << std::setw(internal::kJsonIndent) << f.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 318 | } |
| 319 | |
Devin Jeanpierre | be2f33b | 2021-10-21 12:54:19 +0000 | [diff] [blame] | 320 | // Information about special member functions. |
| 321 | // |
| 322 | // Nontrivial definitions are divided into two: there are nontrivial definitions |
| 323 | // which are nontrivial only due to a member variable which defines the special |
| 324 | // member function, and those which are nontrivial because the operation was |
| 325 | // user defined for the object itself, or for any base class. |
| 326 | // |
Devin Jeanpierre | cd0ba85 | 2021-10-21 12:55:47 +0000 | [diff] [blame] | 327 | // This allows us to sidestep calling C++ implementations of special member |
Devin Jeanpierre | be2f33b | 2021-10-21 12:54:19 +0000 | [diff] [blame] | 328 | // functions in narrow cases: even for a nontrivial special member function, if |
| 329 | // it is kNontrivialMembers, we can directly implement it in Rust in terms of |
| 330 | // the member variables. |
Devin Jeanpierre | 0793127 | 2021-10-05 11:40:13 +0000 | [diff] [blame] | 331 | struct SpecialMemberFunc { |
| 332 | enum class Definition : char { |
| 333 | kTrivial, |
Devin Jeanpierre | be2f33b | 2021-10-21 12:54:19 +0000 | [diff] [blame] | 334 | // Nontrivial, but only because of a member variable with a nontrivial |
| 335 | // special member function. |
| 336 | kNontrivialMembers, |
| 337 | // Nontrivial because of a user-defined special member function in this or a |
| 338 | // base class. (May *also* be nontrivial due to member variables.) |
| 339 | kNontrivialSelf, |
Devin Jeanpierre | 0793127 | 2021-10-05 11:40:13 +0000 | [diff] [blame] | 340 | kDeleted, |
| 341 | }; |
| 342 | |
| 343 | nlohmann::json ToJson() const; |
| 344 | |
| 345 | Definition definition = Definition::kTrivial; |
| 346 | AccessSpecifier access = AccessSpecifier::kPublic; |
| 347 | }; |
| 348 | |
| 349 | std::ostream& operator<<(std::ostream& o, |
| 350 | const SpecialMemberFunc::Definition& definition); |
| 351 | |
| 352 | inline std::ostream& operator<<(std::ostream& o, const SpecialMemberFunc& f) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 353 | return o << std::setw(internal::kJsonIndent) << f.ToJson(); |
Devin Jeanpierre | 0793127 | 2021-10-05 11:40:13 +0000 | [diff] [blame] | 354 | } |
| 355 | |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 356 | // A record (struct, class, union). |
Googler | 949b7d9 | 2021-09-17 07:46:11 +0000 | [diff] [blame] | 357 | struct Record { |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 358 | nlohmann::json ToJson() const; |
| 359 | |
Googler | 949b7d9 | 2021-09-17 07:46:11 +0000 | [diff] [blame] | 360 | Identifier identifier; |
Marcel Hlopko | 264b9ad | 2021-12-02 21:06:44 +0000 | [diff] [blame] | 361 | DeclId id; |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 362 | Label owning_target; |
Michael Forster | 028800b | 2021-10-05 12:39:59 +0000 | [diff] [blame] | 363 | std::optional<std::string> doc_comment; |
Googler | 949b7d9 | 2021-09-17 07:46:11 +0000 | [diff] [blame] | 364 | std::vector<Field> fields; |
Googler | 64e4edb | 2021-12-03 12:17:38 +0000 | [diff] [blame] | 365 | std::vector<Lifetime> lifetime_params; |
Googler | 6986c07 | 2021-09-17 13:54:56 +0000 | [diff] [blame] | 366 | // Size and alignment in bytes. |
| 367 | int64_t size; |
| 368 | int64_t alignment; |
Devin Jeanpierre | b2cd021 | 2021-10-01 07:16:23 +0000 | [diff] [blame] | 369 | |
Devin Jeanpierre | 0793127 | 2021-10-05 11:40:13 +0000 | [diff] [blame] | 370 | // Special member functions. |
| 371 | SpecialMemberFunc copy_constructor = {}; |
| 372 | SpecialMemberFunc move_constructor = {}; |
Devin Jeanpierre | e78b2fb | 2021-10-05 11:40:33 +0000 | [diff] [blame] | 373 | SpecialMemberFunc destructor = {}; |
Devin Jeanpierre | 0793127 | 2021-10-05 11:40:13 +0000 | [diff] [blame] | 374 | |
Devin Jeanpierre | b2cd021 | 2021-10-01 07:16:23 +0000 | [diff] [blame] | 375 | // Whether this type is passed by value as if it were a trivial type (the same |
| 376 | // as it would be if it were a struct in C). |
| 377 | // |
| 378 | // This can be either due to language rules (it *is* a trivial type), or due |
| 379 | // to the usage of a Clang attribute that forces trivial for calls: |
| 380 | // |
| 381 | // * https://eel.is/c++draft/class.temporary#3 |
| 382 | // * https://clang.llvm.org/docs/AttributeReference.html#trivial-abi |
| 383 | bool is_trivial_abi = false; |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 384 | }; |
| 385 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 386 | inline std::ostream& operator<<(std::ostream& o, const Record& r) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 387 | return o << std::setw(internal::kJsonIndent) << r.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 388 | } |
| 389 | |
Michael Forster | 6a184ad | 2021-10-12 13:04:05 +0000 | [diff] [blame] | 390 | // Source code location |
| 391 | struct SourceLoc { |
| 392 | nlohmann::json ToJson() const; |
| 393 | |
| 394 | std::string filename; |
| 395 | uint64 line; |
| 396 | uint64 column; |
| 397 | }; |
| 398 | |
| 399 | inline std::ostream& operator<<(std::ostream& o, const SourceLoc& r) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 400 | return o << std::setw(internal::kJsonIndent) << r.ToJson(); |
Michael Forster | 6a184ad | 2021-10-12 13:04:05 +0000 | [diff] [blame] | 401 | } |
| 402 | |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 403 | // A placeholder for an item that we can't generate bindings for (yet) |
| 404 | struct UnsupportedItem { |
| 405 | nlohmann::json ToJson() const; |
| 406 | |
| 407 | // TODO(forster): We could show the original declaration in the generated |
| 408 | // message (potentially also for successfully imported items). |
| 409 | |
| 410 | // Qualified name of the item for which we couldn't generate bindings |
| 411 | std::string name; |
| 412 | |
| 413 | // Explanation of why we couldn't generate bindings |
| 414 | // TODO(forster): We should support multiple reasons per unsupported item. |
| 415 | std::string message; |
Michael Forster | 6a184ad | 2021-10-12 13:04:05 +0000 | [diff] [blame] | 416 | SourceLoc source_loc; |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 417 | }; |
| 418 | |
| 419 | inline std::ostream& operator<<(std::ostream& o, const UnsupportedItem& r) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 420 | return o << std::setw(internal::kJsonIndent) << r.ToJson(); |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 421 | } |
| 422 | |
Michael Forster | f1dce42 | 2021-10-13 09:50:16 +0000 | [diff] [blame] | 423 | struct Comment { |
| 424 | nlohmann::json ToJson() const; |
| 425 | |
| 426 | std::string text; |
| 427 | }; |
| 428 | |
| 429 | inline std::ostream& operator<<(std::ostream& o, const Comment& r) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 430 | return o << std::setw(internal::kJsonIndent) << r.ToJson(); |
Michael Forster | f1dce42 | 2021-10-13 09:50:16 +0000 | [diff] [blame] | 431 | } |
| 432 | |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 433 | // A complete intermediate representation of bindings for publicly accessible |
| 434 | // declarations of a single C++ library. |
Devin Jeanpierre | 0d5d0d4 | 2021-09-16 10:37:21 +0000 | [diff] [blame] | 435 | struct IR { |
Marcel Hlopko | 42abfc8 | 2021-08-09 07:03:17 +0000 | [diff] [blame] | 436 | nlohmann::json ToJson() const; |
| 437 | |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 438 | template <typename T> |
Googler | 1661eee | 2021-12-01 12:36:19 +0000 | [diff] [blame] | 439 | std::vector<const T*> get_items_if() const { |
| 440 | std::vector<const T*> filtered_items; |
| 441 | for (const auto& item : items) { |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 442 | if (auto* filtered_item = std::get_if<T>(&item)) { |
| 443 | filtered_items.push_back(filtered_item); |
| 444 | } |
| 445 | } |
| 446 | return filtered_items; |
| 447 | } |
| 448 | |
Marcel Hlopko | f1123c8 | 2021-08-19 11:38:52 +0000 | [diff] [blame] | 449 | // Collection of public headers that were used to construct the AST this `IR` |
| 450 | // is generated from. |
Devin Jeanpierre | 0d5d0d4 | 2021-09-16 10:37:21 +0000 | [diff] [blame] | 451 | std::vector<HeaderName> used_headers; |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 452 | Label current_target; |
Michael Forster | f1dce42 | 2021-10-13 09:50:16 +0000 | [diff] [blame] | 453 | std::vector<std::variant<Func, Record, UnsupportedItem, Comment>> items; |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 454 | }; |
| 455 | |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 456 | inline std::ostream& operator<<(std::ostream& o, const IR& ir) { |
Googler | 5618301 | 2021-12-01 11:07:05 +0000 | [diff] [blame] | 457 | return o << std::setw(internal::kJsonIndent) << ir.ToJson(); |
Devin Jeanpierre | 2d5718a | 2021-10-05 11:39:34 +0000 | [diff] [blame] | 458 | } |
Marcel Hlopko | bfd8d32 | 2021-08-02 12:28:52 +0000 | [diff] [blame] | 459 | } // namespace rs_bindings_from_cc |
| 460 | |
| 461 | #endif // CRUBIT_RS_BINDINGS_FROM_CC_IR_H_ |