Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +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 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 5 | #include "rs_bindings_from_cc/importer.h" |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 6 | |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 7 | #include <stdint.h> |
| 8 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 9 | #include <algorithm> |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 10 | #include <cstddef> |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 11 | #include <memory> |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 12 | #include <optional> |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 13 | #include <string> |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 14 | #include <tuple> |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 15 | #include <utility> |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 16 | #include <variant> |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 17 | #include <vector> |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 18 | |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 19 | #include "absl/container/flat_hash_map.h" |
| 20 | #include "absl/container/flat_hash_set.h" |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 21 | #include "absl/log/check.h" |
| 22 | #include "absl/log/log.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 23 | #include "absl/status/status.h" |
| 24 | #include "absl/status/statusor.h" |
| 25 | #include "absl/strings/cord.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 26 | #include "absl/strings/str_cat.h" |
| 27 | #include "absl/strings/str_join.h" |
| 28 | #include "absl/strings/string_view.h" |
| 29 | #include "absl/strings/substitute.h" |
Marco Poletti | c61bcc4 | 2022-04-08 12:54:30 -0700 | [diff] [blame] | 30 | #include "common/status_macros.h" |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 31 | #include "lifetime_annotations/type_lifetimes.h" |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 32 | #include "rs_bindings_from_cc/ast_util.h" |
Marcel Hlopko | 3b254b3 | 2022-03-09 14:10:49 +0000 | [diff] [blame] | 33 | #include "rs_bindings_from_cc/bazel_types.h" |
| 34 | #include "rs_bindings_from_cc/ir.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 35 | #include "clang/AST/ASTContext.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 36 | #include "clang/AST/Decl.h" |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 37 | #include "clang/AST/DeclBase.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 38 | #include "clang/AST/DeclCXX.h" |
Michael VanBemmel | 7a4d4c0 | 2022-07-27 13:21:47 -0700 | [diff] [blame] | 39 | #include "clang/AST/DeclFriend.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 40 | #include "clang/AST/Mangle.h" |
| 41 | #include "clang/AST/RawCommentList.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 42 | #include "clang/AST/Type.h" |
| 43 | #include "clang/Basic/FileManager.h" |
Rosica Dejanovska | 93aeafb | 2022-06-01 07:05:31 -0700 | [diff] [blame] | 44 | #include "clang/Basic/LLVM.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 45 | #include "clang/Basic/OperatorKinds.h" |
| 46 | #include "clang/Basic/SourceLocation.h" |
| 47 | #include "clang/Basic/SourceManager.h" |
| 48 | #include "clang/Basic/Specifiers.h" |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 49 | #include "clang/Sema/Sema.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 50 | #include "llvm/ADT/Optional.h" |
| 51 | #include "llvm/ADT/STLExtras.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 52 | #include "llvm/Support/Casting.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 53 | #include "llvm/Support/Regex.h" |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 54 | |
Marcel Hlopko | f15e8ce | 2022-04-08 08:46:09 -0700 | [diff] [blame] | 55 | namespace crubit { |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 56 | namespace { |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 57 | |
Michael Forster | b836c58 | 2022-01-21 11:20:22 +0000 | [diff] [blame] | 58 | constexpr absl::string_view kTypeStatusPayloadUrl = |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 59 | "type.googleapis.com/devtools.rust.cc_interop.rs_binding_from_cc.type"; |
| 60 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 61 | // Checks if the return value from `GetDeclItem` indicates that the import was |
| 62 | // successful. |
| 63 | absl::Status CheckImportStatus(const std::optional<IR::Item>& item) { |
| 64 | if (!item.has_value()) { |
| 65 | return absl::InvalidArgumentError("The import has been skipped"); |
| 66 | } |
| 67 | if (auto* unsupported = std::get_if<UnsupportedItem>(&*item)) { |
| 68 | return absl::InvalidArgumentError(unsupported->message); |
| 69 | } |
| 70 | return absl::OkStatus(); |
| 71 | } |
Devin Jeanpierre | e971ed7 | 2022-08-09 05:07:04 -0700 | [diff] [blame] | 72 | } // namespace |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 73 | |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 74 | // A mapping of C++ standard types to their equivalent Rust types. |
| 75 | // To produce more idiomatic results, these types receive special handling |
| 76 | // instead of using the generic type mapping mechanism. |
Lukasz Anforowicz | ff16f64 | 2022-05-27 16:56:50 -0700 | [diff] [blame] | 77 | std::optional<absl::string_view> MapKnownCcTypeToRsType( |
| 78 | absl::string_view cc_type) { |
Lukasz Anforowicz | b22917e | 2022-02-16 23:49:59 +0000 | [diff] [blame] | 79 | static const auto* const kWellKnownTypes = |
| 80 | new absl::flat_hash_map<absl::string_view, absl::string_view>({ |
| 81 | {"ptrdiff_t", "isize"}, |
| 82 | {"intptr_t", "isize"}, |
| 83 | {"size_t", "usize"}, |
| 84 | {"uintptr_t", "usize"}, |
| 85 | {"std::ptrdiff_t", "isize"}, |
| 86 | {"std::intptr_t", "isize"}, |
| 87 | {"std::size_t", "usize"}, |
| 88 | {"std::uintptr_t", "usize"}, |
Googler | 4e50488 | 2022-01-13 10:03:19 +0000 | [diff] [blame] | 89 | |
Lukasz Anforowicz | b22917e | 2022-02-16 23:49:59 +0000 | [diff] [blame] | 90 | {"int8_t", "i8"}, |
| 91 | {"int16_t", "i16"}, |
| 92 | {"int32_t", "i32"}, |
| 93 | {"int64_t", "i64"}, |
| 94 | {"std::int8_t", "i8"}, |
| 95 | {"std::int16_t", "i16"}, |
| 96 | {"std::int32_t", "i32"}, |
| 97 | {"std::int64_t", "i64"}, |
Googler | 4e50488 | 2022-01-13 10:03:19 +0000 | [diff] [blame] | 98 | |
Lukasz Anforowicz | b22917e | 2022-02-16 23:49:59 +0000 | [diff] [blame] | 99 | {"uint8_t", "u8"}, |
| 100 | {"uint16_t", "u16"}, |
| 101 | {"uint32_t", "u32"}, |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 102 | |
Lukasz Anforowicz | b22917e | 2022-02-16 23:49:59 +0000 | [diff] [blame] | 103 | {"uint64_t", "u64"}, |
| 104 | {"std::uint8_t", "u8"}, |
| 105 | {"std::uint16_t", "u16"}, |
| 106 | {"std::uint32_t", "u32"}, |
| 107 | {"std::uint64_t", "u64"}, |
Googler | 4e50488 | 2022-01-13 10:03:19 +0000 | [diff] [blame] | 108 | |
Lukasz Anforowicz | b22917e | 2022-02-16 23:49:59 +0000 | [diff] [blame] | 109 | {"char16_t", "u16"}, |
| 110 | {"char32_t", "u32"}, |
| 111 | {"wchar_t", "i32"}, |
| 112 | }); |
| 113 | auto it = kWellKnownTypes->find(cc_type); |
| 114 | if (it == kWellKnownTypes->end()) return std::nullopt; |
| 115 | return it->second; |
| 116 | } |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 117 | |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 118 | namespace { |
| 119 | |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 120 | // Converts clang::CallingConv enum [1] into an equivalent Rust Abi [2, 3, 4]. |
| 121 | // [1] |
| 122 | // https://github.com/llvm/llvm-project/blob/c6a3225bb03b6afc2b63fbf13db3c100406b32ce/clang/include/clang/Basic/Specifiers.h#L262-L283 |
| 123 | // [2] https://doc.rust-lang.org/reference/types/function-pointer.html |
| 124 | // [3] |
| 125 | // https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier |
| 126 | // [4] |
| 127 | // https://github.com/rust-lang/rust/blob/b27ccbc7e1e6a04d749e244a3c13f72ca38e80e7/compiler/rustc_target/src/spec/abi.rs#L49 |
| 128 | absl::StatusOr<absl::string_view> ConvertCcCallConvIntoRsAbi( |
| 129 | clang::CallingConv cc_call_conv) { |
| 130 | switch (cc_call_conv) { |
| 131 | case clang::CC_C: // __attribute__((cdecl)) |
| 132 | // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says |
| 133 | // that: |
| 134 | // - `extern "C"` [...] whatever the default your C compiler supports. |
| 135 | // - `extern "cdecl"` -- The default for x86_32 C code. |
| 136 | // |
| 137 | // We don't support C++ exceptions and therefore we use "C" (rather than |
| 138 | // "C-unwind") - we have no need for unwinding across the FFI boundary - |
| 139 | // e.g. from C++ into Rust frames (or vice versa). |
| 140 | return "C"; |
| 141 | case clang::CC_X86FastCall: // __attribute__((fastcall)) |
| 142 | // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says |
| 143 | // that the fastcall ABI -- corresponds to MSVC's __fastcall and GCC and |
| 144 | // clang's __attribute__((fastcall)). |
| 145 | return "fastcall"; |
| 146 | case clang::CC_X86VectorCall: // __attribute__((vectorcall)) |
| 147 | // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says |
| 148 | // that the vectorcall ABI -- corresponds to MSVC's __vectorcall and |
| 149 | // clang's __attribute__((vectorcall)). |
| 150 | return "vectorcall"; |
| 151 | case clang::CC_X86ThisCall: // __attribute__((thiscall)) |
| 152 | // We don't support C++ exceptions and therefore we use "thiscall" (rather |
| 153 | // than "thiscall-unwind") - we have no need for unwinding across the FFI |
| 154 | // boundary - e.g. from C++ into Rust frames (or vice versa). |
| 155 | return "thiscall"; |
| 156 | case clang::CC_X86StdCall: // __attribute__((stdcall)) |
| 157 | // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says |
| 158 | // extern "stdcall" -- The default for the Win32 API on x86_32. |
| 159 | // |
| 160 | // We don't support C++ exceptions and therefore we use "stdcall" (rather |
| 161 | // than "stdcall-unwind") - we have no need for unwinding across the FFI |
| 162 | // boundary - e.g. from C++ into Rust frames (or vice versa). |
| 163 | return "stdcall"; |
| 164 | case clang::CC_Win64: // __attribute__((ms_abi)) |
| 165 | // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says |
| 166 | // extern "win64" -- The default for C code on x86_64 Windows. |
| 167 | return "win64"; |
| 168 | case clang::CC_AAPCS: // __attribute__((pcs("aapcs"))) |
| 169 | case clang::CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) |
| 170 | // TODO(lukasza): Should both map to "aapcs"? |
| 171 | break; |
| 172 | case clang::CC_X86_64SysV: // __attribute__((sysv_abi)) |
| 173 | // TODO(lukasza): Maybe this is "sysv64"? |
| 174 | break; |
| 175 | case clang::CC_X86Pascal: // __attribute__((pascal)) |
| 176 | case clang::CC_X86RegCall: // __attribute__((regcall)) |
| 177 | case clang::CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) |
| 178 | case clang::CC_SpirFunction: // default for OpenCL functions on SPIR target |
| 179 | case clang::CC_OpenCLKernel: // inferred for OpenCL kernels |
| 180 | case clang::CC_Swift: // __attribute__((swiftcall)) |
| 181 | case clang::CC_SwiftAsync: // __attribute__((swiftasynccall)) |
| 182 | case clang::CC_PreserveMost: // __attribute__((preserve_most)) |
| 183 | case clang::CC_PreserveAll: // __attribute__((preserve_all)) |
| 184 | case clang::CC_AArch64VectorCall: // __attribute__((aarch64_vector_pcs)) |
Marcel Hlopko | f80bf51 | 2022-05-12 01:20:33 -0700 | [diff] [blame] | 185 | // TODO(hlopko): Uncomment once we integrate the upstream change that |
| 186 | // introduced it: |
| 187 | // case clang::CC_AArch64SVEPCS: __attribute__((aarch64_sve_pcs)) |
| 188 | |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 189 | // These don't seem to have any Rust equivalents. |
| 190 | break; |
Marcel Hlopko | f80bf51 | 2022-05-12 01:20:33 -0700 | [diff] [blame] | 191 | default: |
Googler | 75c7ad0 | 2022-05-23 13:27:49 -0700 | [diff] [blame] | 192 | break; |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 193 | } |
| 194 | return absl::UnimplementedError( |
| 195 | absl::StrCat("Unsupported calling convention: ", |
| 196 | absl::string_view( |
| 197 | clang::FunctionType::getNameForCallConv(cc_call_conv)))); |
| 198 | } |
| 199 | |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 200 | } // namespace |
| 201 | |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 202 | // Multiple IR items can be associated with the same source location (e.g. the |
| 203 | // implicitly defined constructors and assignment operators). To produce |
| 204 | // deterministic output, we order such items based on GetDeclOrder. The order |
| 205 | // is somewhat arbitrary, but we still try to make it aesthetically pleasing |
| 206 | // (e.g. constructors go before assignment operators; default constructor goes |
| 207 | // first, etc.). |
| 208 | static int GetDeclOrder(const clang::Decl* decl) { |
| 209 | if (clang::isa<clang::RecordDecl>(decl)) { |
| 210 | return decl->getDeclContext()->isRecord() ? 101 : 100; |
| 211 | } |
| 212 | |
| 213 | if (auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) { |
| 214 | return ctor->isDefaultConstructor() ? 202 |
| 215 | : ctor->isCopyConstructor() ? 203 |
| 216 | : ctor->isMoveConstructor() ? 204 |
| 217 | : 299; |
| 218 | } |
| 219 | |
| 220 | if (clang::isa<clang::CXXDestructorDecl>(decl)) { |
| 221 | return 306; |
| 222 | } |
| 223 | |
| 224 | if (auto* method = clang::dyn_cast<clang::CXXMethodDecl>(decl)) { |
| 225 | return method->isCopyAssignmentOperator() ? 401 |
| 226 | : method->isMoveAssignmentOperator() ? 402 |
| 227 | : 499; |
| 228 | } |
| 229 | |
| 230 | return 999; |
| 231 | } |
| 232 | |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 233 | class Importer::SourceOrderKey { |
| 234 | public: |
| 235 | SourceOrderKey(clang::SourceRange source_range, int decl_order = 0, |
| 236 | std::string name = "") |
| 237 | : source_range_(source_range), decl_order_(decl_order), name_(name) {} |
| 238 | |
| 239 | SourceOrderKey(const SourceOrderKey&) = default; |
| 240 | SourceOrderKey& operator=(const SourceOrderKey&) = default; |
| 241 | |
| 242 | bool isBefore(const SourceOrderKey& other, |
| 243 | const clang::SourceManager& sm) const { |
| 244 | if (!source_range_.isValid() || !other.source_range_.isValid()) { |
| 245 | if (source_range_.isValid() != other.source_range_.isValid()) |
| 246 | return !source_range_.isValid() && other.source_range_.isValid(); |
| 247 | } else { |
| 248 | if (source_range_.getBegin() != other.source_range_.getBegin()) { |
| 249 | return sm.isBeforeInTranslationUnit(source_range_.getBegin(), |
| 250 | other.source_range_.getBegin()); |
| 251 | } |
| 252 | if (source_range_.getEnd() != other.source_range_.getEnd()) { |
| 253 | return sm.isBeforeInTranslationUnit(source_range_.getEnd(), |
| 254 | other.source_range_.getEnd()); |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | if (decl_order_ < other.decl_order_) { |
| 259 | return true; |
| 260 | } else if (decl_order_ > other.decl_order_) { |
| 261 | return false; |
| 262 | } |
| 263 | return name_ < other.name_; |
| 264 | } |
| 265 | |
| 266 | private: |
| 267 | clang::SourceRange source_range_; |
| 268 | int decl_order_; |
| 269 | std::string name_; |
| 270 | }; |
| 271 | |
| 272 | Importer::SourceOrderKey Importer::GetSourceOrderKey( |
| 273 | const clang::Decl* decl) const { |
| 274 | return SourceOrderKey(decl->getSourceRange(), GetDeclOrder(decl), |
| 275 | GetNameForSourceOrder(decl)); |
| 276 | } |
| 277 | |
| 278 | Importer::SourceOrderKey Importer::GetSourceOrderKey( |
| 279 | const clang::RawComment* comment) const { |
| 280 | return SourceOrderKey(comment->getSourceRange()); |
| 281 | } |
| 282 | |
| 283 | class Importer::SourceLocationComparator { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 284 | public: |
| 285 | const bool operator()(const clang::SourceLocation& a, |
| 286 | const clang::SourceLocation& b) const { |
| 287 | return b.isValid() && a.isValid() && sm.isBeforeInTranslationUnit(a, b); |
| 288 | } |
| 289 | const bool operator()(const clang::RawComment* a, |
| 290 | const clang::SourceLocation& b) const { |
| 291 | return this->operator()(a->getBeginLoc(), b); |
| 292 | } |
| 293 | const bool operator()(const clang::SourceLocation& a, |
| 294 | const clang::RawComment* b) const { |
| 295 | return this->operator()(a, b->getBeginLoc()); |
| 296 | } |
| 297 | const bool operator()(const clang::RawComment* a, |
| 298 | const clang::RawComment* b) const { |
| 299 | return this->operator()(a->getBeginLoc(), b->getBeginLoc()); |
| 300 | } |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 301 | |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 302 | using OrderedItemId = std::pair<SourceOrderKey, ItemId>; |
| 303 | using OrderedItem = std::pair<SourceOrderKey, IR::Item>; |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 304 | |
| 305 | template <typename OrderedItemOrId> |
| 306 | bool operator()(const OrderedItemOrId& a, const OrderedItemOrId& b) const { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 307 | auto a_source_order = a.first; |
| 308 | auto b_source_order = b.first; |
| 309 | return a_source_order.isBefore(b_source_order, sm); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 310 | } |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 311 | SourceLocationComparator(const clang::SourceManager& sm) : sm(sm) {} |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 312 | |
| 313 | private: |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 314 | const clang::SourceManager& sm; |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 315 | }; |
| 316 | |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 317 | static std::vector<clang::Decl*> GetCanonicalChildren( |
| 318 | const clang::DeclContext* decl_context) { |
| 319 | std::vector<clang::Decl*> result; |
| 320 | for (clang::Decl* decl : decl_context->decls()) { |
| 321 | if (const auto* linkage_spec_decl = |
| 322 | llvm::dyn_cast<clang::LinkageSpecDecl>(decl)) { |
| 323 | llvm::move(GetCanonicalChildren(linkage_spec_decl), |
| 324 | std::back_inserter(result)); |
| 325 | continue; |
| 326 | } |
| 327 | |
Lukasz Anforowicz | 38310f3 | 2022-09-09 11:17:52 -0700 | [diff] [blame] | 328 | // `CXXRecordDeclImporter::Import` supports class template specializations |
| 329 | // but such import should only be triggered when |
| 330 | // `Importer::ConvertTemplateSpecializationType` is called (which means that |
| 331 | // the specialization is actually used in an explicit instantiation via |
| 332 | // `cc_template!` macro, in a type alias, or as a parameter type of a |
| 333 | // function, etc.). |
| 334 | if (clang::isa<clang::ClassTemplateSpecializationDecl>(decl)) continue; |
| 335 | |
Lukasz Anforowicz | 02ce0f7 | 2022-09-02 12:10:26 -0700 | [diff] [blame] | 336 | // In general we only import (and include as children) canonical decls. |
| 337 | // Namespaces are exempted to ensure that we process every one of |
| 338 | // (potential) multiple namespace blocks with the same name. |
| 339 | if (decl == decl->getCanonicalDecl() || |
| 340 | clang::isa<clang::NamespaceDecl>(decl)) { |
| 341 | result.push_back(decl); |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 342 | } |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 343 | } |
| 344 | |
| 345 | return result; |
| 346 | } |
| 347 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 348 | std::vector<ItemId> Importer::GetItemIdsInSourceOrder( |
| 349 | clang::Decl* parent_decl) { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 350 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 351 | std::vector<SourceLocationComparator::OrderedItemId> items; |
| 352 | auto compare_locations = SourceLocationComparator(sm); |
| 353 | |
| 354 | // We are only interested in comments within this decl context. |
| 355 | std::vector<const clang::RawComment*> comments_in_range( |
| 356 | llvm::lower_bound(comments_, parent_decl->getBeginLoc(), |
| 357 | compare_locations), |
| 358 | llvm::upper_bound(comments_, parent_decl->getEndLoc(), |
| 359 | compare_locations)); |
| 360 | |
| 361 | std::map<clang::SourceLocation, const clang::RawComment*, |
| 362 | SourceLocationComparator> |
| 363 | ordered_comments(compare_locations); |
| 364 | for (auto& comment : comments_in_range) { |
| 365 | ordered_comments.insert({comment->getBeginLoc(), comment}); |
| 366 | } |
| 367 | |
| 368 | absl::flat_hash_set<ItemId> visited_item_ids; |
Marcel Hlopko | d4678de | 2022-05-25 01:38:13 -0700 | [diff] [blame] | 369 | |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 370 | auto* decl_context = clang::cast<clang::DeclContext>(parent_decl); |
| 371 | for (auto decl : GetCanonicalChildren(decl_context)) { |
Rosica Dejanovska | 001852d | 2022-06-07 14:19:41 -0700 | [diff] [blame] | 372 | auto item = GetDeclItem(decl); |
| 373 | // We generated IR for top level items coming from different targets, |
| 374 | // however we shouldn't generate bindings for them, so we don't add them |
| 375 | // to ir.top_level_item_ids. |
| 376 | if (decl_context->isTranslationUnit() && !IsFromCurrentTarget(decl)) |
| 377 | continue; |
| 378 | // Only add item ids for decls that can be successfully imported. |
| 379 | if (item.has_value()) { |
| 380 | auto item_id = GenerateItemId(decl); |
| 381 | // TODO(rosica): Drop this check when we start importing also other |
| 382 | // redecls, not just the canonical |
| 383 | if (visited_item_ids.find(item_id) == visited_item_ids.end()) { |
| 384 | visited_item_ids.insert(item_id); |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 385 | items.push_back({GetSourceOrderKey(decl), item_id}); |
Rosica Dejanovska | 001852d | 2022-06-07 14:19:41 -0700 | [diff] [blame] | 386 | } |
| 387 | } |
| 388 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 389 | // We remove comments attached to a child decl or that are within a child |
| 390 | // decl. |
| 391 | if (auto raw_comment = ctx_.getRawCommentForDeclNoCache(decl)) { |
| 392 | ordered_comments.erase(raw_comment->getBeginLoc()); |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 393 | } |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 394 | ordered_comments.erase(ordered_comments.lower_bound(decl->getBeginLoc()), |
| 395 | ordered_comments.upper_bound(decl->getEndLoc())); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 396 | } |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 397 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 398 | for (auto& [_, comment] : ordered_comments) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 399 | items.push_back({GetSourceOrderKey(comment), GenerateItemId(comment)}); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 400 | } |
Dmitri Gribenko | 620bc91 | 2022-04-22 03:38:04 -0700 | [diff] [blame] | 401 | llvm::sort(items, compare_locations); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 402 | |
| 403 | std::vector<ItemId> ordered_item_ids; |
| 404 | ordered_item_ids.reserve(items.size()); |
| 405 | for (auto& ordered_item : items) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 406 | ordered_item_ids.push_back(ordered_item.second); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 407 | } |
| 408 | return ordered_item_ids; |
| 409 | } |
| 410 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 411 | std::vector<ItemId> Importer::GetOrderedItemIdsOfTemplateInstantiations() |
| 412 | const { |
| 413 | std::vector<SourceLocationComparator::OrderedItemId> items; |
| 414 | items.reserve(class_template_instantiations_for_current_target_.size()); |
| 415 | for (const auto* decl : class_template_instantiations_for_current_target_) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 416 | items.push_back({GetSourceOrderKey(decl), GenerateItemId(decl)}); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 417 | } |
| 418 | |
| 419 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 420 | auto compare_locations = SourceLocationComparator(sm); |
| 421 | llvm::sort(items, compare_locations); |
| 422 | |
| 423 | std::vector<ItemId> ordered_item_ids; |
| 424 | ordered_item_ids.reserve(items.size()); |
| 425 | for (const auto& ordered_item : items) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 426 | ordered_item_ids.push_back(ordered_item.second); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 427 | } |
| 428 | return ordered_item_ids; |
| 429 | } |
| 430 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 431 | void Importer::ImportFreeComments() { |
| 432 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 433 | for (const auto& header : invocation_.entry_headers_) { |
| 434 | if (auto file = sm.getFileManager().getFile(header.IncludePath())) { |
| 435 | if (auto comments_in_file = ctx_.Comments.getCommentsInFile( |
| 436 | sm.getOrCreateFileID(*file, clang::SrcMgr::C_User))) { |
| 437 | for (const auto& [_, comment] : *comments_in_file) { |
| 438 | comments_.push_back(comment); |
| 439 | } |
| 440 | } |
| 441 | } |
| 442 | } |
Dmitri Gribenko | 620bc91 | 2022-04-22 03:38:04 -0700 | [diff] [blame] | 443 | llvm::sort(comments_, SourceLocationComparator(sm)); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 444 | } |
| 445 | |
| 446 | void Importer::Import(clang::TranslationUnitDecl* translation_unit_decl) { |
| 447 | ImportFreeComments(); |
| 448 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 449 | std::vector<SourceLocationComparator::OrderedItem> ordered_items; |
| 450 | |
| 451 | for (auto& comment : comments_) { |
| 452 | ordered_items.push_back( |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 453 | {GetSourceOrderKey(comment), |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 454 | Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics()), |
| 455 | .id = GenerateItemId(comment)}}); |
| 456 | } |
| 457 | |
| 458 | ImportDeclsFromDeclContext(translation_unit_decl); |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 459 | for (const auto& [decl, item] : import_cache_) { |
| 460 | if (item.has_value()) { |
| 461 | if (std::holds_alternative<UnsupportedItem>(*item) && |
| 462 | !IsFromCurrentTarget(decl)) { |
| 463 | continue; |
| 464 | } |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 465 | ordered_items.push_back({GetSourceOrderKey(decl), *item}); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 466 | } |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 467 | } |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 468 | |
Dmitri Gribenko | 620bc91 | 2022-04-22 03:38:04 -0700 | [diff] [blame] | 469 | llvm::sort(ordered_items, SourceLocationComparator(sm)); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 470 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 471 | invocation_.ir_.items.reserve(ordered_items.size()); |
| 472 | for (auto& ordered_item : ordered_items) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 473 | invocation_.ir_.items.push_back(ordered_item.second); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 474 | } |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 475 | invocation_.ir_.top_level_item_ids = |
| 476 | GetItemIdsInSourceOrder(translation_unit_decl); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 477 | |
| 478 | // TODO(b/222001243): Consider placing the generated template instantiations |
| 479 | // into a separate namespace (maybe `crubit::instantiated_templates` ?). |
| 480 | llvm::copy(GetOrderedItemIdsOfTemplateInstantiations(), |
| 481 | std::back_inserter(invocation_.ir_.top_level_item_ids)); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 482 | } |
| 483 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 484 | void Importer::ImportDeclsFromDeclContext( |
| 485 | const clang::DeclContext* decl_context) { |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 486 | for (auto decl : GetCanonicalChildren(decl_context)) { |
| 487 | GetDeclItem(decl); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 488 | } |
| 489 | } |
| 490 | |
Michael Forster | 1b50637 | 2022-04-12 11:31:54 -0700 | [diff] [blame] | 491 | std::optional<IR::Item> Importer::GetDeclItem(clang::Decl* decl) { |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 492 | // TODO: Move `decl->getCanonicalDecl()` from callers into here. |
Michael Forster | 1b50637 | 2022-04-12 11:31:54 -0700 | [diff] [blame] | 493 | auto it = import_cache_.find(decl); |
| 494 | if (it == import_cache_.end()) { |
| 495 | it = import_cache_.insert({decl, ImportDecl(decl)}).first; |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 496 | } |
Michael Forster | 1b50637 | 2022-04-12 11:31:54 -0700 | [diff] [blame] | 497 | return it->second; |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 498 | } |
| 499 | |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 500 | std::optional<IR::Item> Importer::ImportDecl(clang::Decl* decl) { |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 501 | std::optional<IR::Item> result; |
| 502 | for (auto& importer : decl_importers_) { |
| 503 | if (importer->CanImport(decl)) { |
| 504 | result = importer->ImportDecl(decl); |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | if (auto* record_decl = clang::dyn_cast<clang::CXXRecordDecl>(decl)) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 509 | // TODO(forster): Should we even visit the nested decl if we couldn't |
| 510 | // import the parent? For now we have tests that check that we generate |
| 511 | // error messages for those decls, so we're visiting. |
| 512 | ImportDeclsFromDeclContext(record_decl); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 513 | } |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 514 | |
| 515 | return result; |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 516 | } |
| 517 | |
Kinuko Yasuda | 6ff59f1 | 2022-08-11 08:41:45 -0700 | [diff] [blame] | 518 | std::optional<IR::Item> Importer::GetImportedItem(const clang::Decl* decl) { |
| 519 | auto it = import_cache_.find(decl); |
| 520 | if (it != import_cache_.end()) { |
| 521 | return it->second; |
| 522 | } |
| 523 | return std::nullopt; |
| 524 | } |
| 525 | |
Googler | 6c3de12 | 2022-03-28 11:40:41 +0000 | [diff] [blame] | 526 | BazelLabel Importer::GetOwningTarget(const clang::Decl* decl) const { |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 527 | // Template instantiations need to be generated in the target that triggered |
| 528 | // the instantiation (not in the target where the template is defined). |
| 529 | if (IsFullClassTemplateSpecializationOrChild(decl)) { |
| 530 | return invocation_.target_; |
| 531 | } |
| 532 | |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 533 | clang::SourceManager& source_manager = ctx_.getSourceManager(); |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 534 | auto source_location = decl->getLocation(); |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 535 | |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 536 | // If the header this decl comes from is not associated with a target we |
| 537 | // consider it a textual header. In that case we go up the include stack |
| 538 | // until we find a header that has an owning target. |
| 539 | |
Rosica Dejanovska | 381d103 | 2022-02-03 22:19:54 +0000 | [diff] [blame] | 540 | while (source_location.isValid()) { |
Rosica Dejanovska | 503d7dd | 2022-02-01 20:37:49 +0000 | [diff] [blame] | 541 | if (source_location.isMacroID()) { |
| 542 | source_location = source_manager.getExpansionLoc(source_location); |
| 543 | } |
| 544 | auto id = source_manager.getFileID(source_location); |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 545 | llvm::Optional<llvm::StringRef> filename = |
| 546 | source_manager.getNonBuiltinFilenameForID(id); |
| 547 | if (!filename) { |
Marcel Hlopko | 457bdef | 2022-05-18 06:01:49 -0700 | [diff] [blame] | 548 | return BazelLabel("//:_nothing_should_depend_on_private_builtin_hdrs"); |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 549 | } |
| 550 | if (filename->startswith("./")) { |
| 551 | filename = filename->substr(2); |
| 552 | } |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 553 | |
| 554 | if (auto target = invocation_.header_target(HeaderName(filename->str()))) { |
| 555 | return *target; |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 556 | } |
| 557 | source_location = source_manager.getIncludeLoc(id); |
Marcel Hlopko | 4c660dd | 2021-12-02 09:52:47 +0000 | [diff] [blame] | 558 | } |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 559 | |
Googler | 6c3de12 | 2022-03-28 11:40:41 +0000 | [diff] [blame] | 560 | return BazelLabel("//:virtual_clang_resource_dir_target"); |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 561 | } |
| 562 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 563 | bool Importer::IsFromCurrentTarget(const clang::Decl* decl) const { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 564 | return invocation_.target_ == GetOwningTarget(decl); |
Marcel Hlopko | 4c660dd | 2021-12-02 09:52:47 +0000 | [diff] [blame] | 565 | } |
| 566 | |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 567 | IR::Item Importer::ImportUnsupportedItem(const clang::Decl* decl, |
| 568 | std::string error) { |
| 569 | std::string name = "unnamed"; |
| 570 | if (const auto* named_decl = clang::dyn_cast<clang::NamedDecl>(decl)) { |
| 571 | name = named_decl->getQualifiedNameAsString(); |
| 572 | } |
| 573 | SourceLoc source_loc = ConvertSourceLocation(decl->getBeginLoc()); |
Rosica Dejanovska | d638cf5 | 2022-03-23 15:45:01 +0000 | [diff] [blame] | 574 | return UnsupportedItem{.name = name, |
| 575 | .message = error, |
| 576 | .source_loc = source_loc, |
| 577 | .id = GenerateItemId(decl)}; |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 578 | } |
| 579 | |
| 580 | IR::Item Importer::ImportUnsupportedItem(const clang::Decl* decl, |
| 581 | std::set<std::string> errors) { |
| 582 | return ImportUnsupportedItem(decl, absl::StrJoin(errors, "\n\n")); |
| 583 | } |
| 584 | |
Lukasz Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 585 | static bool ShouldKeepCommentLine(absl::string_view line) { |
| 586 | // Based on https://clang.llvm.org/extra/clang-tidy/: |
| 587 | llvm::Regex patterns_to_ignore( |
| 588 | "^[[:space:]/]*" // Whitespace, or extra // |
| 589 | "(NOLINT|NOLINTNEXTLINE|NOLINTBEGIN|NOLINTEND)" |
| 590 | "(\\([^)[:space:]]*\\)?)?" // Optional (...) |
| 591 | "[[:space:]]*$"); // Whitespace |
| 592 | return !patterns_to_ignore.match(line); |
| 593 | } |
| 594 | |
Lukasz Anforowicz | 3b4be12 | 2022-03-16 00:09:35 +0000 | [diff] [blame] | 595 | llvm::Optional<std::string> Importer::GetComment( |
| 596 | const clang::Decl* decl) const { |
Michael Forster | 409d941 | 2021-10-07 08:35:29 +0000 | [diff] [blame] | 597 | // This does currently not distinguish between different types of comments. |
| 598 | // In general it is not possible in C++ to reliably only extract doc comments. |
| 599 | // This is going to be a heuristic that needs to be tuned over time. |
| 600 | |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 601 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 602 | clang::RawComment* raw_comment = ctx_.getRawCommentForDeclNoCache(decl); |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 603 | |
| 604 | if (raw_comment == nullptr) { |
| 605 | return {}; |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 606 | } |
Lukasz Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 607 | |
| 608 | std::string raw_comment_text = |
| 609 | raw_comment->getFormattedText(sm, sm.getDiagnostics()); |
| 610 | std::string cleaned_comment_text = absl::StrJoin( |
| 611 | absl::StrSplit(raw_comment_text, '\n', ShouldKeepCommentLine), "\n"); |
Lukasz Anforowicz | 3b4be12 | 2022-03-16 00:09:35 +0000 | [diff] [blame] | 612 | if (cleaned_comment_text.empty()) return {}; |
| 613 | return cleaned_comment_text; |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 614 | } |
| 615 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 616 | SourceLoc Importer::ConvertSourceLocation(clang::SourceLocation loc) const { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 617 | auto& sm = ctx_.getSourceManager(); |
Michael Forster | d3ef1e9 | 2021-10-12 16:15:31 +0000 | [diff] [blame] | 618 | |
Googler | c8a8e73 | 2021-10-19 07:49:24 +0000 | [diff] [blame] | 619 | clang::StringRef filename = sm.getFilename(loc); |
Michael Forster | d3ef1e9 | 2021-10-12 16:15:31 +0000 | [diff] [blame] | 620 | if (filename.startswith("./")) { |
| 621 | filename = filename.substr(2); |
| 622 | } |
| 623 | |
| 624 | return SourceLoc{.filename = filename.str(), |
| 625 | .line = sm.getSpellingLineNumber(loc), |
| 626 | .column = sm.getSpellingColumnNumber(loc)}; |
| 627 | } |
| 628 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 629 | absl::StatusOr<MappedType> Importer::ConvertTemplateSpecializationType( |
| 630 | const clang::TemplateSpecializationType* type) { |
| 631 | // Qualifiers are handled separately in TypeMapper::ConvertQualType(). |
| 632 | std::string type_string = clang::QualType(type, 0).getAsString(); |
| 633 | |
| 634 | auto* specialization_decl = |
| 635 | clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>( |
| 636 | type->getAsCXXRecordDecl()); |
| 637 | if (!specialization_decl) { |
| 638 | return absl::InvalidArgumentError(absl::Substitute( |
| 639 | "Template specialization '$0' without an associated record decl " |
| 640 | "is not supported.", |
| 641 | type_string)); |
| 642 | } |
| 643 | |
Lukasz Anforowicz | 3a2026b | 2022-06-09 09:08:42 -0700 | [diff] [blame] | 644 | if (HasBeenAlreadySuccessfullyImported(specialization_decl)) |
| 645 | return ConvertTypeDecl(specialization_decl); |
| 646 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 647 | // `Sema::isCompleteType` will try to instantiate the class template as a |
| 648 | // side-effect and we rely on this here. `decl->getDefinition()` can |
| 649 | // return nullptr before the call to sema and return its definition |
| 650 | // afterwards. |
Lukasz Anforowicz | 38310f3 | 2022-09-09 11:17:52 -0700 | [diff] [blame] | 651 | (void)sema_.isCompleteType(specialization_decl->getLocation(), |
| 652 | ctx_.getRecordType(specialization_decl)); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 653 | |
| 654 | // TODO(lukasza): Limit specialization depth? (e.g. using |
| 655 | // `isSpecializationDepthGreaterThan` from earlier prototypes). |
| 656 | |
| 657 | absl::Status import_status = |
| 658 | CheckImportStatus(GetDeclItem(specialization_decl)); |
| 659 | if (!import_status.ok()) { |
| 660 | return absl::InvalidArgumentError(absl::Substitute( |
| 661 | "Failed to create bindings for template specialization type $0: $1", |
| 662 | type_string, import_status.message())); |
| 663 | } |
| 664 | |
Lukasz Anforowicz | 38310f3 | 2022-09-09 11:17:52 -0700 | [diff] [blame] | 665 | // Store `specialization_decl`s so that they will get included in |
| 666 | // IR::top_level_item_ids. |
| 667 | class_template_instantiations_for_current_target_.insert(specialization_decl); |
Lukasz Anforowicz | 42ab93b | 2022-08-31 11:17:59 -0700 | [diff] [blame] | 668 | |
Lukasz Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 669 | return ConvertTypeDecl(specialization_decl); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 670 | } |
| 671 | |
Lukasz Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 672 | absl::StatusOr<MappedType> Importer::ConvertTypeDecl( |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 673 | const clang::TypeDecl* decl) const { |
Lukasz Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 674 | if (!HasBeenAlreadySuccessfullyImported(decl)) { |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 675 | return absl::NotFoundError(absl::Substitute( |
| 676 | "No generated bindings found for '$0'", decl->getNameAsString())); |
| 677 | } |
| 678 | |
Rosica Dejanovska | d638cf5 | 2022-03-23 15:45:01 +0000 | [diff] [blame] | 679 | ItemId decl_id = GenerateItemId(decl); |
Lukasz Anforowicz | 58f2711 | 2022-03-15 17:51:03 +0000 | [diff] [blame] | 680 | return MappedType::WithDeclId(decl_id); |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 681 | } |
| 682 | |
Lukasz Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 683 | absl::StatusOr<MappedType> Importer::ConvertType( |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 684 | const clang::Type* type, |
Martin Brænne | 1a207c5 | 2022-04-19 00:05:38 -0700 | [diff] [blame] | 685 | std::optional<clang::tidy::lifetimes::ValueLifetimes>& lifetimes, |
Lukasz Anforowicz | 14732b2 | 2022-06-02 09:11:08 -0700 | [diff] [blame] | 686 | bool nullable) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 687 | // Qualifiers are handled separately in ConvertQualType(). |
| 688 | std::string type_string = clang::QualType(type, 0).getAsString(); |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 689 | |
Lukasz Anforowicz | ff16f64 | 2022-05-27 16:56:50 -0700 | [diff] [blame] | 690 | if (auto maybe_mapped_type = MapKnownCcTypeToRsType(type_string); |
Lukasz Anforowicz | b22917e | 2022-02-16 23:49:59 +0000 | [diff] [blame] | 691 | maybe_mapped_type.has_value()) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 692 | return MappedType::Simple(std::string(*maybe_mapped_type), type_string); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 693 | } else if (type->isPointerType() || type->isLValueReferenceType() || |
| 694 | type->isRValueReferenceType()) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 695 | clang::QualType pointee_type = type->getPointeeType(); |
Lukasz Anforowicz | 92c81c3 | 2022-03-04 19:03:56 +0000 | [diff] [blame] | 696 | std::optional<LifetimeId> lifetime; |
| 697 | if (lifetimes.has_value()) { |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 698 | lifetime = |
| 699 | LifetimeId(lifetimes->GetPointeeLifetimes().GetLifetime().Id()); |
| 700 | lifetimes = lifetimes->GetPointeeLifetimes().GetValueLifetimes(); |
Lukasz Anforowicz | 92c81c3 | 2022-03-04 19:03:56 +0000 | [diff] [blame] | 701 | } |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 702 | if (const auto* func_type = |
Lukasz Anforowicz | 92c81c3 | 2022-03-04 19:03:56 +0000 | [diff] [blame] | 703 | pointee_type->getAs<clang::FunctionProtoType>()) { |
| 704 | if (lifetime.has_value() && |
Martin Brænne | 1a207c5 | 2022-04-19 00:05:38 -0700 | [diff] [blame] | 705 | lifetime->value() != |
| 706 | clang::tidy::lifetimes::Lifetime::Static().Id()) { |
Lukasz Anforowicz | 92c81c3 | 2022-03-04 19:03:56 +0000 | [diff] [blame] | 707 | return absl::UnimplementedError( |
| 708 | absl::StrCat("Function pointers with non-'static lifetimes are " |
| 709 | "not supported: ", |
| 710 | type_string)); |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 711 | } |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 712 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 713 | clang::StringRef cc_call_conv = |
| 714 | clang::FunctionType::getNameForCallConv(func_type->getCallConv()); |
Lukasz Anforowicz | d41a4e9 | 2022-03-17 17:08:57 +0000 | [diff] [blame] | 715 | CRUBIT_ASSIGN_OR_RETURN( |
| 716 | absl::string_view rs_abi, |
| 717 | ConvertCcCallConvIntoRsAbi(func_type->getCallConv())); |
| 718 | CRUBIT_ASSIGN_OR_RETURN( |
| 719 | MappedType mapped_return_type, |
| 720 | ConvertQualType(func_type->getReturnType(), lifetimes)); |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 721 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 722 | std::vector<MappedType> mapped_param_types; |
| 723 | for (const clang::QualType& param_type : func_type->getParamTypes()) { |
Lukasz Anforowicz | d41a4e9 | 2022-03-17 17:08:57 +0000 | [diff] [blame] | 724 | CRUBIT_ASSIGN_OR_RETURN(MappedType mapped_param_type, |
| 725 | ConvertQualType(param_type, lifetimes)); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 726 | mapped_param_types.push_back(std::move(mapped_param_type)); |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 727 | } |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 728 | |
| 729 | if (type->isPointerType()) { |
| 730 | return MappedType::FuncPtr(cc_call_conv, rs_abi, lifetime, |
| 731 | std::move(mapped_return_type), |
| 732 | std::move(mapped_param_types)); |
| 733 | } else { |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 734 | CHECK(type->isLValueReferenceType()); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 735 | return MappedType::FuncRef(cc_call_conv, rs_abi, lifetime, |
| 736 | std::move(mapped_return_type), |
| 737 | std::move(mapped_param_types)); |
| 738 | } |
| 739 | } |
| 740 | |
Lukasz Anforowicz | d41a4e9 | 2022-03-17 17:08:57 +0000 | [diff] [blame] | 741 | CRUBIT_ASSIGN_OR_RETURN(MappedType mapped_pointee_type, |
| 742 | ConvertQualType(pointee_type, lifetimes)); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 743 | if (type->isPointerType()) { |
| 744 | return MappedType::PointerTo(std::move(mapped_pointee_type), lifetime, |
| 745 | nullable); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 746 | } else if (type->isLValueReferenceType()) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 747 | return MappedType::LValueReferenceTo(std::move(mapped_pointee_type), |
| 748 | lifetime); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 749 | } else { |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 750 | CHECK(type->isRValueReferenceType()); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 751 | if (!lifetime.has_value()) { |
| 752 | return absl::UnimplementedError( |
| 753 | "Unsupported type: && without lifetime"); |
| 754 | } |
| 755 | return MappedType::RValueReferenceTo(std::move(mapped_pointee_type), |
| 756 | *lifetime); |
Googler | 61dce3b | 2021-12-02 09:16:32 +0000 | [diff] [blame] | 757 | } |
Googler | b6c0fe0 | 2021-12-01 10:55:31 +0000 | [diff] [blame] | 758 | } else if (const auto* builtin_type = |
Googler | 06f2c9a | 2022-01-05 12:00:47 +0000 | [diff] [blame] | 759 | // Use getAsAdjusted instead of getAs so we don't desugar |
| 760 | // typedefs. |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 761 | type->getAsAdjusted<clang::BuiltinType>()) { |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 762 | switch (builtin_type->getKind()) { |
| 763 | case clang::BuiltinType::Bool: |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 764 | return MappedType::Simple("bool", "bool"); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 765 | break; |
| 766 | case clang::BuiltinType::Float: |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 767 | return MappedType::Simple("f32", "float"); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 768 | break; |
| 769 | case clang::BuiltinType::Double: |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 770 | return MappedType::Simple("f64", "double"); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 771 | break; |
| 772 | case clang::BuiltinType::Void: |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 773 | return MappedType::Void(); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 774 | break; |
| 775 | default: |
| 776 | if (builtin_type->isIntegerType()) { |
Lukasz Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 777 | auto size = ctx_.getTypeSize(builtin_type); |
Googler | 06f2c9a | 2022-01-05 12:00:47 +0000 | [diff] [blame] | 778 | if (size == 8 || size == 16 || size == 32 || size == 64) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 779 | return MappedType::Simple( |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 780 | absl::Substitute( |
| 781 | "$0$1", builtin_type->isSignedInteger() ? 'i' : 'u', size), |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 782 | type_string); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 783 | } |
| 784 | } |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 785 | } |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 786 | } else if (const auto* tag_type = type->getAsAdjusted<clang::TagType>()) { |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 787 | return ConvertTypeDecl(tag_type->getDecl()); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 788 | } else if (const auto* typedef_type = |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 789 | type->getAsAdjusted<clang::TypedefType>()) { |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 790 | return ConvertTypeDecl(typedef_type->getDecl()); |
Lukasz Anforowicz | 14732b2 | 2022-06-02 09:11:08 -0700 | [diff] [blame] | 791 | } else if (const auto* tst_type = |
| 792 | type->getAs<clang::TemplateSpecializationType>()) { |
| 793 | return ConvertTemplateSpecializationType(tst_type); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 794 | } else if (const auto* subst_type = |
| 795 | type->getAs<clang::SubstTemplateTypeParmType>()) { |
| 796 | return ConvertQualType(subst_type->getReplacementType(), lifetimes); |
Lukasz Anforowicz | 8f59068 | 2022-05-17 12:39:20 -0700 | [diff] [blame] | 797 | } else if (const auto* deduced_type = type->getAs<clang::DeducedType>()) { |
| 798 | // Deduction should have taken place earlier (e.g. via DeduceReturnType |
| 799 | // called from FunctionDeclImporter::Import). |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 800 | CHECK(deduced_type->isDeduced()); |
Lukasz Anforowicz | 8f59068 | 2022-05-17 12:39:20 -0700 | [diff] [blame] | 801 | return ConvertQualType(deduced_type->getDeducedType(), lifetimes); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 802 | } |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 803 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 804 | return absl::UnimplementedError(absl::StrCat( |
| 805 | "Unsupported clang::Type class '", type->getTypeClassName(), "'")); |
| 806 | } |
| 807 | |
Devin Jeanpierre | e971ed7 | 2022-08-09 05:07:04 -0700 | [diff] [blame] | 808 | // Returns a QualType with leading ElaboratedType nodes removed. |
| 809 | // |
| 810 | // This is analogous to getDesugaredType but *only* removes ElaboratedType |
| 811 | // sugar. |
| 812 | static clang::QualType GetUnelaboratedType(clang::QualType qual_type, |
| 813 | clang::ASTContext& ast_context) { |
| 814 | clang::QualifierCollector qualifiers; |
| 815 | while (true) { |
| 816 | const clang::Type* type = qualifiers.strip(qual_type); |
| 817 | if (const auto* elaborated = llvm::dyn_cast<clang::ElaboratedType>(type)) { |
| 818 | qual_type = elaborated->getNamedType(); |
| 819 | continue; |
| 820 | } |
| 821 | |
| 822 | return ast_context.getQualifiedType(type, qualifiers); |
| 823 | } |
| 824 | } |
| 825 | |
Lukasz Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 826 | absl::StatusOr<MappedType> Importer::ConvertQualType( |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 827 | clang::QualType qual_type, |
Martin Brænne | 1a207c5 | 2022-04-19 00:05:38 -0700 | [diff] [blame] | 828 | std::optional<clang::tidy::lifetimes::ValueLifetimes>& lifetimes, |
Lukasz Anforowicz | 14732b2 | 2022-06-02 09:11:08 -0700 | [diff] [blame] | 829 | bool nullable) { |
Devin Jeanpierre | e971ed7 | 2022-08-09 05:07:04 -0700 | [diff] [blame] | 830 | qual_type = GetUnelaboratedType(std::move(qual_type), ctx_); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 831 | std::string type_string = qual_type.getAsString(); |
| 832 | absl::StatusOr<MappedType> type = |
| 833 | ConvertType(qual_type.getTypePtr(), lifetimes, nullable); |
| 834 | if (!type.ok()) { |
| 835 | absl::Status error = absl::UnimplementedError(absl::Substitute( |
| 836 | "Unsupported type '$0': $1", type_string, type.status().message())); |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 837 | error.SetPayload(kTypeStatusPayloadUrl, absl::Cord(type_string)); |
| 838 | return error; |
| 839 | } |
| 840 | |
Lukasz Anforowicz | 0c3f8b2 | 2022-02-15 14:56:40 +0000 | [diff] [blame] | 841 | // Handle cv-qualification. |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 842 | type->cc_type.is_const = qual_type.isConstQualified(); |
Lukasz Anforowicz | 0c3f8b2 | 2022-02-15 14:56:40 +0000 | [diff] [blame] | 843 | if (qual_type.isVolatileQualified()) { |
| 844 | return absl::UnimplementedError( |
| 845 | absl::StrCat("Unsupported `volatile` qualifier: ", type_string)); |
| 846 | } |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 847 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 848 | return type; |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 849 | } |
| 850 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 851 | std::string Importer::GetMangledName(const clang::NamedDecl* named_decl) const { |
Lukasz Anforowicz | 3f13397 | 2022-09-01 09:01:02 -0700 | [diff] [blame] | 852 | if (auto record_decl = clang::dyn_cast<clang::RecordDecl>(named_decl)) { |
| 853 | // Mangled record names are used to 1) provide valid Rust identifiers for |
| 854 | // C++ template specializations, and 2) help build unique names for virtual |
| 855 | // upcast thunks. |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 856 | llvm::SmallString<128> storage; |
| 857 | llvm::raw_svector_ostream buffer(storage); |
Lukasz Anforowicz | 3f13397 | 2022-09-01 09:01:02 -0700 | [diff] [blame] | 858 | mangler_->mangleTypeName(ctx_.getRecordType(record_decl), buffer); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 859 | |
| 860 | // The Itanium mangler does not provide a way to get the mangled |
| 861 | // representation of a type. Instead, we call mangleTypeName() that |
| 862 | // returns the name of the RTTI typeinfo symbol, and remove the _ZTS |
Lukasz Anforowicz | 3f13397 | 2022-09-01 09:01:02 -0700 | [diff] [blame] | 863 | // prefix. |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 864 | constexpr llvm::StringRef kZtsPrefix = "_ZTS"; |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 865 | CHECK(buffer.str().take_front(4) == kZtsPrefix); |
Lukasz Anforowicz | 3f13397 | 2022-09-01 09:01:02 -0700 | [diff] [blame] | 866 | llvm::StringRef mangled_record_name = |
| 867 | buffer.str().drop_front(kZtsPrefix.size()); |
| 868 | |
| 869 | if (clang::isa<clang::ClassTemplateSpecializationDecl>(named_decl)) { |
| 870 | // We prepend __CcTemplateInst to reduce chances of conflict |
| 871 | // with regular C and C++ structs. |
| 872 | constexpr llvm::StringRef kCcTemplatePrefix = "__CcTemplateInst"; |
| 873 | return llvm::formatv("{0}{1}", kCcTemplatePrefix, mangled_record_name); |
| 874 | } |
| 875 | return std::string(mangled_record_name); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 876 | } |
| 877 | |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 878 | clang::GlobalDecl decl; |
| 879 | |
| 880 | // There are only three named decl types that don't work with the GlobalDecl |
| 881 | // unary constructor: GPU kernels (which do not exist in standard C++, so we |
| 882 | // ignore), constructors, and destructors. GlobalDecl does not support |
| 883 | // constructors and destructors from the unary constructor because there is |
| 884 | // more than one global declaration for a given constructor or destructor! |
| 885 | // |
| 886 | // * (Ctor|Dtor)_Complete is a function which constructs / destroys the |
| 887 | // entire object. This is what we want. :) |
| 888 | // * Dtor_Deleting is a function which additionally calls operator delete. |
| 889 | // * (Ctor|Dtor)_Base is a function which constructs/destroys the object but |
| 890 | // NOT including virtual base class subobjects. |
| 891 | // * (Ctor|Dtor)_Comdat: I *believe* this is the identifier used to |
| 892 | // deduplicate inline functions, and is not callable. |
| 893 | // * Dtor_(Copying|Default)Closure: These only exist in the MSVC++ ABI, |
| 894 | // which we don't support for now. I don't know when they are used. |
| 895 | // |
| 896 | // It was hard to piece this together, so writing it down here to explain why |
| 897 | // we magically picked the *_Complete variants. |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 898 | if (auto dtor = clang::dyn_cast<clang::CXXDestructorDecl>(named_decl)) { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 899 | decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete); |
| 900 | } else if (auto ctor = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 901 | clang::dyn_cast<clang::CXXConstructorDecl>(named_decl)) { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 902 | decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete); |
| 903 | } else { |
| 904 | decl = clang::GlobalDecl(named_decl); |
| 905 | } |
| 906 | |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 907 | std::string name; |
| 908 | llvm::raw_string_ostream stream(name); |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 909 | mangler_->mangleName(decl, stream); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 910 | stream.flush(); |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 911 | return name; |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 912 | } |
| 913 | |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 914 | std::string Importer::GetNameForSourceOrder(const clang::Decl* decl) const { |
| 915 | // Implicit class template specializations and their methods all have the |
| 916 | // same source location. In order to provide deterministic order of the |
| 917 | // respective items in generated source code, we additionally use the |
| 918 | // mangled names when sorting the items. |
| 919 | if (auto* class_template_specialization_decl = |
| 920 | clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) { |
| 921 | return GetMangledName(class_template_specialization_decl); |
| 922 | } else if (auto* func_decl = clang::dyn_cast<clang::FunctionDecl>(decl)) { |
| 923 | return GetMangledName(func_decl); |
Michael VanBemmel | 7a4d4c0 | 2022-07-27 13:21:47 -0700 | [diff] [blame] | 924 | } else if (auto* friend_decl = clang::dyn_cast<clang::FriendDecl>(decl)) { |
| 925 | if (auto* named_decl = friend_decl->getFriendDecl()) { |
| 926 | if (auto function_template_decl = |
| 927 | clang::dyn_cast<clang::FunctionTemplateDecl>(named_decl)) { |
| 928 | // Reach through the function template declaration for a function that |
| 929 | // can be mangled. |
| 930 | named_decl = function_template_decl->getTemplatedDecl(); |
| 931 | } |
| 932 | return GetMangledName(named_decl); |
| 933 | } else { |
| 934 | // This FriendDecl names a type. We don't import those, so we don't have |
| 935 | // to assign a name. |
| 936 | return ""; |
| 937 | } |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 938 | } else { |
| 939 | return ""; |
| 940 | } |
| 941 | } |
| 942 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 943 | std::optional<UnqualifiedIdentifier> Importer::GetTranslatedName( |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 944 | const clang::NamedDecl* named_decl) const { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 945 | switch (named_decl->getDeclName().getNameKind()) { |
| 946 | case clang::DeclarationName::Identifier: { |
| 947 | auto name = std::string(named_decl->getName()); |
Lukasz Anforowicz | ab03e56 | 2022-05-16 11:18:02 -0700 | [diff] [blame] | 948 | if (const clang::ParmVarDecl* param_decl = |
| 949 | clang::dyn_cast<clang::ParmVarDecl>(named_decl)) { |
| 950 | int param_pos = param_decl->getFunctionScopeIndex(); |
| 951 | if (name.empty()) { |
Lukasz Anforowicz | 0c816f1 | 2021-12-15 17:41:49 +0000 | [diff] [blame] | 952 | return {Identifier(absl::StrCat("__param_", param_pos))}; |
| 953 | } |
Lukasz Anforowicz | ab03e56 | 2022-05-16 11:18:02 -0700 | [diff] [blame] | 954 | if (auto* sttpt = param_decl->getType() |
| 955 | ->getAs<clang::SubstTemplateTypeParmType>(); |
| 956 | sttpt && sttpt->getReplacedParameter()->isParameterPack()) { |
| 957 | // Avoid giving the same name to all parameters expanded from a pack. |
| 958 | return {Identifier(absl::StrCat("__", name, "_", param_pos))}; |
| 959 | } |
| 960 | } |
| 961 | if (name.empty()) { |
Kinuko Yasuda | 8dd8464 | 2022-08-17 09:19:47 -0700 | [diff] [blame] | 962 | auto anon_decl_name = anon_decl_names_.find(named_decl); |
| 963 | if (anon_decl_name != anon_decl_names_.end()) { |
| 964 | return {Identifier(std::string(anon_decl_name->second))}; |
| 965 | } |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 966 | return std::nullopt; |
| 967 | } |
| 968 | return {Identifier(std::move(name))}; |
| 969 | } |
| 970 | case clang::DeclarationName::CXXConstructorName: |
| 971 | return {SpecialName::kConstructor}; |
| 972 | case clang::DeclarationName::CXXDestructorName: |
| 973 | return {SpecialName::kDestructor}; |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 974 | case clang::DeclarationName::CXXOperatorName: |
| 975 | switch (named_decl->getDeclName().getCXXOverloadedOperator()) { |
| 976 | case clang::OO_None: |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 977 | LOG(FATAL) << "No OO_None expected under CXXOperatorName branch"; |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 978 | return std::nullopt; |
| 979 | case clang::NUM_OVERLOADED_OPERATORS: |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 980 | LOG(FATAL) << "No NUM_OVERLOADED_OPERATORS expected at runtime"; |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 981 | return std::nullopt; |
| 982 | // clang-format off |
| 983 | #define OVERLOADED_OPERATOR(name, spelling, ...) \ |
| 984 | case clang::OO_##name: { \ |
Lukasz Anforowicz | 9c663ca | 2022-02-09 01:33:31 +0000 | [diff] [blame] | 985 | return {Operator(spelling)}; \ |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 986 | } |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 987 | #include "clang/Basic/OperatorKinds.def" |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 988 | #undef OVERLOADED_OPERATOR |
| 989 | // clang-format on |
| 990 | } |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 991 | LOG(FATAL) << "The `switch` above should handle all cases"; |
Lukasz Anforowicz | 34ad7f7 | 2022-03-17 16:05:28 +0000 | [diff] [blame] | 992 | return std::nullopt; |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 993 | default: |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 994 | // To be implemented later: CXXConversionFunctionName. |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 995 | // There are also e.g. literal operators, deduction guides, etc., but |
| 996 | // we might not need to implement them at all. Full list at: |
| 997 | // https://clang.llvm.org/doxygen/classclang_1_1DeclarationName.html#a9ab322d434446b43379d39e41af5cbe3 |
| 998 | return std::nullopt; |
Devin Jeanpierre | e78b2fb | 2021-10-05 11:40:33 +0000 | [diff] [blame] | 999 | } |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 1000 | } |
| 1001 | |
Lukasz Anforowicz | 0233f98 | 2022-05-27 16:38:20 -0700 | [diff] [blame] | 1002 | void Importer::MarkAsSuccessfullyImported(const clang::TypeDecl* decl) { |
Lukasz Anforowicz | 23fdfad | 2022-05-27 16:43:43 -0700 | [diff] [blame] | 1003 | known_type_decls_.insert( |
| 1004 | clang::cast<clang::TypeDecl>(decl->getCanonicalDecl())); |
Lukasz Anforowicz | 0233f98 | 2022-05-27 16:38:20 -0700 | [diff] [blame] | 1005 | } |
| 1006 | |
Lukasz Anforowicz | 5258f76 | 2022-05-27 16:14:46 -0700 | [diff] [blame] | 1007 | bool Importer::HasBeenAlreadySuccessfullyImported( |
| 1008 | const clang::TypeDecl* decl) const { |
Lukasz Anforowicz | 23fdfad | 2022-05-27 16:43:43 -0700 | [diff] [blame] | 1009 | return known_type_decls_.contains( |
| 1010 | clang::cast<clang::TypeDecl>(decl->getCanonicalDecl())); |
Lukasz Anforowicz | 5258f76 | 2022-05-27 16:14:46 -0700 | [diff] [blame] | 1011 | } |
| 1012 | |
Marcel Hlopko | f15e8ce | 2022-04-08 08:46:09 -0700 | [diff] [blame] | 1013 | } // namespace crubit |