blob: 302d32927afe586758ce12b45e2b95340e9da7b0 [file] [log] [blame]
Marcel Hlopkobfd8d322021-08-02 12:28:52 +00001// 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 Hlopko20f4ce42021-11-02 08:20:00 +000014#include <stdint.h>
15
16#include <optional>
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +000017#include <string>
Marcel Hlopkobfd8d322021-08-02 12:28:52 +000018#include <utility>
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000019#include <variant>
Marcel Hlopkobfd8d322021-08-02 12:28:52 +000020#include <vector>
21
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000022#include "base/integral_types.h"
Marcel Hlopkobfd8d322021-08-02 12:28:52 +000023#include "base/logging.h"
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +000024#include "third_party/absl/strings/string_view.h"
Marcel Hlopko42abfc82021-08-09 07:03:17 +000025#include "third_party/json/src/json.hpp"
Marcel Hlopko9c150da2021-11-12 10:30:03 +000026#include "util/intops/strong_int.h"
Marcel Hlopkobfd8d322021-08-02 12:28:52 +000027
28namespace rs_bindings_from_cc {
29
Devin Jeanpierre5c87a722021-09-16 10:35:58 +000030namespace internal {
31inline constexpr absl::string_view kRustPtrMut = "*mut";
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +000032inline constexpr absl::string_view kRustPtrConst = "*const";
33inline constexpr absl::string_view kCcPtr = "*";
Devin Jeanpierre5c87a722021-09-16 10:35:58 +000034} // namespace internal
35
Marcel Hlopkof1123c82021-08-19 11:38:52 +000036// A name of a public header of the C++ library.
37class HeaderName {
38 public:
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +000039 explicit HeaderName(std::string name) : name_(std::move(name)) {}
Marcel Hlopkof1123c82021-08-19 11:38:52 +000040
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +000041 absl::string_view IncludePath() const { return name_; }
Marcel Hlopkof1123c82021-08-19 11:38:52 +000042
43 nlohmann::json ToJson() const;
44
Marcel Hlopko7aa38a72021-11-11 07:39:51 +000045 template <typename H>
46 friend H AbslHashValue(H h, const HeaderName& header_name) {
47 return H::combine(std::move(h), header_name.name_);
48 }
49
Marcel Hlopkof1123c82021-08-19 11:38:52 +000050 private:
51 // Header pathname in the format suitable for a google3-relative quote
52 // include.
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +000053 std::string name_;
Marcel Hlopkof1123c82021-08-19 11:38:52 +000054};
55
Marcel Hlopko7aa38a72021-11-11 07:39:51 +000056inline bool operator==(const HeaderName& lhs, const HeaderName& rhs) {
57 return lhs.IncludePath() == rhs.IncludePath();
58}
59
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +000060inline std::ostream& operator<<(std::ostream& o, const HeaderName& h) {
61 return o << h.ToJson();
62}
63
Marcel Hlopko9c150da2021-11-12 10:30:03 +000064// An int uniquely representing a Decl. Since our IR goes through the JSON
65// serialization/deserialization at the moment, we need a way to restore graph
66// edges that don't follow the JSON tree structure (for example between types
67// and records). We use DeclIds for this.
68DEFINE_STRONG_INT_TYPE(DeclId, uintptr_t);
69
Devin Jeanpierre09c6f452021-09-29 07:34:24 +000070// A C++ type involved in the bindings. It has the knowledge of how the type
71// is spelled in C++.
72struct CcType {
Marcel Hlopko42abfc82021-08-09 07:03:17 +000073 nlohmann::json ToJson() const;
Devin Jeanpierre09c6f452021-09-29 07:34:24 +000074 // The name of the type. For example, int or void.
75 std::string name;
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +000076
Marcel Hlopko9c150da2021-11-12 10:30:03 +000077 // Id of a decl that this type corresponds to. `nullopt` for primitive types.
78 std::optional<DeclId> decl_id = std::nullopt;
79
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +000080 // The C++ const-qualification for the type.
81 //
Devin Jeanpierrec6c62eb2021-09-29 07:13:35 +000082 // Note: there are two types for which cv-qualification does not do anything:
83 // references and functions. if `T` is either a function type like `void()`,
84 // or a reference type like `int&`, then `T`, `const T`, and `volatile T` are
85 // all the same type in C++.
Devin Jeanpierre09c6f452021-09-29 07:34:24 +000086 bool is_const = false;
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +000087
Devin Jeanpierre5c87a722021-09-16 10:35:58 +000088 // Type parameters for a generic type. Examples:
Devin Jeanpierre09c6f452021-09-29 07:34:24 +000089 // int has no type parameters.
Devin Jeanpierre5c87a722021-09-16 10:35:58 +000090 // int* has a single type parameter, int.
91 // tuple<int, float> has two type parameters, int and float.
Devin Jeanpierre09c6f452021-09-29 07:34:24 +000092 std::vector<CcType> type_params = {};
93};
94
95// A Rust type involved in the bindings. It has the knowledge of how the type
96// is spelled in Rust.
97struct RsType {
98 nlohmann::json ToJson() const;
99
100 // The name of the type. For example, i32 or ().
101 std::string name;
102
Marcel Hlopko9c150da2021-11-12 10:30:03 +0000103 // Id of a decl that this type corresponds to. `nullopt` for primitive types.
104 std::optional<DeclId> decl_id = std::nullopt;
105
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000106 // Type parameters for a generic type. Examples:
107 // i32 has no type parameters.
108 // *mut i32 has a single type parameter, i32.
109 // (i32, f32) has two type parameters, i32 and f32.
110 std::vector<RsType> type_params = {};
111};
112
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000113inline std::ostream& operator<<(std::ostream& o, const RsType& type) {
114 return o << type.ToJson();
115}
116
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000117// A type involved in the bindings. The rs_type and cc_type will be treated
118// as interchangeable during bindings, and so should share the same layout.
119//
120// For example: a C++ pointer may be a usize in Rust, rather than a pointer, but
121// should almost certainly not be a u8, because u8 and pointers are sized and
122// aligned differently.
123struct MappedType {
124 static MappedType Void() { return Simple("()", "void"); }
125
126 /// Returns the MappedType for a non-templated/generic, non-cv-qualified type.
127 /// For example, Void() is Simple("()", "void").
128 static MappedType Simple(std::string rs_name, std::string cc_name) {
129 return MappedType{RsType{rs_name}, CcType{cc_name}};
130 }
131
Marcel Hlopko9c150da2021-11-12 10:30:03 +0000132 static MappedType WithDeclIds(std::string rs_name, DeclId rs_decl_id,
133 std::string cc_name, DeclId cc_decl_id) {
134 return MappedType{RsType{std::move(rs_name), rs_decl_id},
135 CcType{std::move(cc_name), cc_decl_id}};
136 }
137
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000138 static MappedType PointerTo(MappedType pointee_type) {
139 absl::string_view rs_name = pointee_type.cc_type.is_const
140 ? internal::kRustPtrConst
141 : internal::kRustPtrMut;
142 auto pointer_type =
143 Simple(std::string(rs_name), std::string(internal::kCcPtr));
144 pointer_type.rs_type.type_params.push_back(std::move(pointee_type.rs_type));
145 pointer_type.cc_type.type_params.push_back(std::move(pointee_type.cc_type));
146 return pointer_type;
147 }
148
149 bool IsVoid() const { return rs_type.name == "()"; }
150
151 nlohmann::json ToJson() const;
152
153 RsType rs_type;
154 CcType cc_type;
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000155};
156
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000157inline std::ostream& operator<<(std::ostream& o, const MappedType& type) {
158 return o << type.ToJson();
159}
160
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000161// An identifier involved in bindings.
162//
163// Examples:
164// Identifier of C++'s `int32_t Add(int32_t a, int32_t b)` will be
165// `Identifier("add")`.
166//
167// Invariants:
168// `identifier` cannot be empty.
169class Identifier {
170 public:
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +0000171 explicit Identifier(std::string identifier)
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000172 : identifier_(std::move(identifier)) {
173 CHECK(!identifier_.empty()) << "Identifier name cannot be empty.";
174 }
175
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +0000176 absl::string_view Ident() const { return identifier_; }
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000177
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000178 nlohmann::json ToJson() const;
179
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000180 private:
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +0000181 std::string identifier_;
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000182};
183
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000184inline std::ostream& operator<<(std::ostream& o, const Identifier& id) {
185 return o << id.Ident();
186}
187
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000188// A function parameter.
189//
190// Examples:
191// FuncParam of a C++ function `void Foo(int32_t a);` will be
Devin Jeanpierre29a25f12021-09-15 11:54:32 +0000192// `FuncParam{.type=Type{"i32", "int32_t"}, .identifier=Identifier("foo"))`.
Devin Jeanpierre601f14f2021-09-15 11:53:18 +0000193struct FuncParam {
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000194 nlohmann::json ToJson() const;
195
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000196 MappedType type;
Devin Jeanpierre601f14f2021-09-15 11:53:18 +0000197 Identifier identifier;
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000198};
199
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000200inline std::ostream& operator<<(std::ostream& o, const FuncParam& param) {
201 return o << param.ToJson();
202}
203
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000204enum SpecialName {
205 kDestructor,
206 kConstructor,
207};
208
209std::ostream& operator<<(std::ostream& o, const SpecialName& special_name);
210
211// A generalized notion of identifier, or an "Unqualified Identifier" in C++
212// jargon: https://en.cppreference.com/w/cpp/language/identifiers
213//
214// Note that constructors are given a separate variant, so that we can treat
215// them differently. After all, they are not invoked or defined like normal
216// functions.
217using UnqualifiedIdentifier = std::variant<Identifier, SpecialName>;
218
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000219struct MemberFuncMetadata {
220 enum ReferenceQualification : char {
221 kLValue, // void Foo() &;
222 kRValue, // void Foo() &&;
223 kUnqualified, // void Foo();
224 };
225
226 struct InstanceMethodMetadata {
227 ReferenceQualification reference = kUnqualified;
228 bool is_const = false;
229 bool is_virtual = false;
230 };
231
232 nlohmann::json ToJson() const;
233
234 // The type that this is a member function for.
235 Identifier for_type;
236
237 // Qualifiers for the instance method.
238 //
239 // If null, this is a static method.
240 std::optional<InstanceMethodMetadata> instance_method_metadata;
241};
242
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000243// A function involved in the bindings.
Devin Jeanpierre4d33b592021-09-15 11:53:32 +0000244struct Func {
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000245 nlohmann::json ToJson() const;
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000246
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000247 UnqualifiedIdentifier name;
Marcel Hlopko9c150da2021-11-12 10:30:03 +0000248 DeclId decl_id;
Michael Forster409d9412021-10-07 08:35:29 +0000249 std::optional<std::string> doc_comment;
Devin Jeanpierre4d33b592021-09-15 11:53:32 +0000250 std::string mangled_name;
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000251 MappedType return_type;
Devin Jeanpierre4d33b592021-09-15 11:53:32 +0000252 std::vector<FuncParam> params;
253 bool is_inline;
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000254 // If null, this is not a member function.
255 std::optional<MemberFuncMetadata> member_func_metadata;
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000256};
257
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000258inline std::ostream& operator<<(std::ostream& o, const Func& f) {
259 return o << f.ToJson();
260}
261
Googler2e85f342021-09-17 07:04:07 +0000262// Access specifier for a member or base class.
263enum AccessSpecifier {
264 kPublic,
265 kProtected,
266 kPrivate,
267};
268
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000269std::ostream& operator<<(std::ostream& o, const AccessSpecifier& access);
270
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000271// A field (non-static member variable) of a record.
Michael Forster6e95ad32021-09-15 21:01:21 +0000272struct Field {
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000273 nlohmann::json ToJson() const;
274
Michael Forster6e95ad32021-09-15 21:01:21 +0000275 Identifier identifier;
Michael Forstercc5941a2021-10-07 07:12:24 +0000276 std::optional<std::string> doc_comment;
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000277 MappedType type;
Googler2e85f342021-09-17 07:04:07 +0000278 AccessSpecifier access;
Googler6986c072021-09-17 13:54:56 +0000279 // Field offset in bits.
280 uint64_t offset;
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000281};
282
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000283inline std::ostream& operator<<(std::ostream& o, const Field& f) {
284 return o << f.ToJson();
285}
286
Devin Jeanpierrebe2f33b2021-10-21 12:54:19 +0000287// Information about special member functions.
288//
289// Nontrivial definitions are divided into two: there are nontrivial definitions
290// which are nontrivial only due to a member variable which defines the special
291// member function, and those which are nontrivial because the operation was
292// user defined for the object itself, or for any base class.
293//
Devin Jeanpierrecd0ba852021-10-21 12:55:47 +0000294// This allows us to sidestep calling C++ implementations of special member
Devin Jeanpierrebe2f33b2021-10-21 12:54:19 +0000295// functions in narrow cases: even for a nontrivial special member function, if
296// it is kNontrivialMembers, we can directly implement it in Rust in terms of
297// the member variables.
Devin Jeanpierre07931272021-10-05 11:40:13 +0000298struct SpecialMemberFunc {
299 enum class Definition : char {
300 kTrivial,
Devin Jeanpierrebe2f33b2021-10-21 12:54:19 +0000301 // Nontrivial, but only because of a member variable with a nontrivial
302 // special member function.
303 kNontrivialMembers,
304 // Nontrivial because of a user-defined special member function in this or a
305 // base class. (May *also* be nontrivial due to member variables.)
306 kNontrivialSelf,
Devin Jeanpierre07931272021-10-05 11:40:13 +0000307 kDeleted,
308 };
309
310 nlohmann::json ToJson() const;
311
312 Definition definition = Definition::kTrivial;
313 AccessSpecifier access = AccessSpecifier::kPublic;
314};
315
316std::ostream& operator<<(std::ostream& o,
317 const SpecialMemberFunc::Definition& definition);
318
319inline std::ostream& operator<<(std::ostream& o, const SpecialMemberFunc& f) {
320 return o << f.ToJson();
321}
322
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000323// A record (struct, class, union).
Googler949b7d92021-09-17 07:46:11 +0000324struct Record {
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000325 nlohmann::json ToJson() const;
326
Googler949b7d92021-09-17 07:46:11 +0000327 Identifier identifier;
Marcel Hlopko9c150da2021-11-12 10:30:03 +0000328 DeclId decl_id;
Michael Forster028800b2021-10-05 12:39:59 +0000329 std::optional<std::string> doc_comment;
Googler949b7d92021-09-17 07:46:11 +0000330 std::vector<Field> fields;
Googler6986c072021-09-17 13:54:56 +0000331 // Size and alignment in bytes.
332 int64_t size;
333 int64_t alignment;
Devin Jeanpierreb2cd0212021-10-01 07:16:23 +0000334
Devin Jeanpierre07931272021-10-05 11:40:13 +0000335 // Special member functions.
336 SpecialMemberFunc copy_constructor = {};
337 SpecialMemberFunc move_constructor = {};
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000338 SpecialMemberFunc destructor = {};
Devin Jeanpierre07931272021-10-05 11:40:13 +0000339
Devin Jeanpierreb2cd0212021-10-01 07:16:23 +0000340 // Whether this type is passed by value as if it were a trivial type (the same
341 // as it would be if it were a struct in C).
342 //
343 // This can be either due to language rules (it *is* a trivial type), or due
344 // to the usage of a Clang attribute that forces trivial for calls:
345 //
346 // * https://eel.is/c++draft/class.temporary#3
347 // * https://clang.llvm.org/docs/AttributeReference.html#trivial-abi
348 bool is_trivial_abi = false;
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000349};
350
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000351inline std::ostream& operator<<(std::ostream& o, const Record& r) {
352 return o << r.ToJson();
353}
354
Michael Forster6a184ad2021-10-12 13:04:05 +0000355// Source code location
356struct SourceLoc {
357 nlohmann::json ToJson() const;
358
359 std::string filename;
360 uint64 line;
361 uint64 column;
362};
363
364inline std::ostream& operator<<(std::ostream& o, const SourceLoc& r) {
365 return o << r.ToJson();
366}
367
Michael Forster523dbd42021-10-12 11:05:44 +0000368// A placeholder for an item that we can't generate bindings for (yet)
369struct UnsupportedItem {
370 nlohmann::json ToJson() const;
371
372 // TODO(forster): We could show the original declaration in the generated
373 // message (potentially also for successfully imported items).
374
375 // Qualified name of the item for which we couldn't generate bindings
376 std::string name;
377
378 // Explanation of why we couldn't generate bindings
379 // TODO(forster): We should support multiple reasons per unsupported item.
380 std::string message;
Michael Forster6a184ad2021-10-12 13:04:05 +0000381 SourceLoc source_loc;
Michael Forster523dbd42021-10-12 11:05:44 +0000382};
383
384inline std::ostream& operator<<(std::ostream& o, const UnsupportedItem& r) {
385 return o << r.ToJson();
386}
387
Michael Forsterf1dce422021-10-13 09:50:16 +0000388struct Comment {
389 nlohmann::json ToJson() const;
390
391 std::string text;
392};
393
394inline std::ostream& operator<<(std::ostream& o, const Comment& r) {
395 return o << r.ToJson();
396}
397
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000398// A complete intermediate representation of bindings for publicly accessible
399// declarations of a single C++ library.
Devin Jeanpierre0d5d0d42021-09-16 10:37:21 +0000400struct IR {
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000401 nlohmann::json ToJson() const;
402
Michael Forster523dbd42021-10-12 11:05:44 +0000403 template <typename T>
404 std::vector<T*> get_items_if() {
405 std::vector<T*> filtered_items;
406 for (auto& item : items) {
407 if (auto* filtered_item = std::get_if<T>(&item)) {
408 filtered_items.push_back(filtered_item);
409 }
410 }
411 return filtered_items;
412 }
413
Marcel Hlopkof1123c82021-08-19 11:38:52 +0000414 // Collection of public headers that were used to construct the AST this `IR`
415 // is generated from.
Devin Jeanpierre0d5d0d42021-09-16 10:37:21 +0000416 std::vector<HeaderName> used_headers;
Michael Forsterf1dce422021-10-13 09:50:16 +0000417 std::vector<std::variant<Func, Record, UnsupportedItem, Comment>> items;
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000418};
419
Devin Jeanpierre2d5718a2021-10-05 11:39:34 +0000420inline std::ostream& operator<<(std::ostream& o, const IR& ir) {
421 return o << ir.ToJson();
422}
Marcel Hlopkobfd8d322021-08-02 12:28:52 +0000423} // namespace rs_bindings_from_cc
424
425#endif // CRUBIT_RS_BINDINGS_FROM_CC_IR_H_