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> |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 16 | #include <vector> |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 17 | |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 18 | #include "base/logging.h" |
Devin Jeanpierre | d3f959f | 2021-10-27 18:47:50 +0000 | [diff] [blame] | 19 | #include "rs_bindings_from_cc/ast_convert.h" |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 20 | #include "rs_bindings_from_cc/bazel_types.h" |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 21 | #include "rs_bindings_from_cc/ir.h" |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 22 | #include "third_party/absl/container/flat_hash_map.h" |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 23 | #include "third_party/absl/container/flat_hash_set.h" |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 24 | #include "third_party/absl/status/status.h" |
| 25 | #include "third_party/absl/status/statusor.h" |
| 26 | #include "third_party/absl/strings/cord.h" |
Lukasz Anforowicz | 0c816f1 | 2021-12-15 17:41:49 +0000 | [diff] [blame] | 27 | #include "third_party/absl/strings/str_cat.h" |
Lukasz Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 28 | #include "third_party/absl/strings/str_join.h" |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 29 | #include "third_party/absl/strings/string_view.h" |
Michael Forster | 1de27b8 | 2021-09-17 07:22:22 +0000 | [diff] [blame] | 30 | #include "third_party/absl/strings/substitute.h" |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 31 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/ASTContext.h" |
Devin Jeanpierre | b69bcae | 2022-02-03 09:45:50 +0000 | [diff] [blame] | 32 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/Attrs.inc" |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 33 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/CXXInheritance.h" |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 34 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/Decl.h" |
Googler | 2e85f34 | 2021-09-17 07:04:07 +0000 | [diff] [blame] | 35 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h" |
Googler | 846e1fc | 2022-01-10 13:14:57 +0000 | [diff] [blame] | 36 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclTemplate.h" |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 37 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/Mangle.h" |
Michael Forster | 028800b | 2021-10-05 12:39:59 +0000 | [diff] [blame] | 38 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/RawCommentList.h" |
Googler | 6986c07 | 2021-09-17 13:54:56 +0000 | [diff] [blame] | 39 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/RecordLayout.h" |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 40 | #include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h" |
Michael Forster | 7b628b1 | 2022-01-27 17:48:57 +0000 | [diff] [blame] | 41 | #include "third_party/llvm/llvm-project/clang/include/clang/Basic/FileManager.h" |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 42 | #include "third_party/llvm/llvm-project/clang/include/clang/Basic/OperatorKinds.h" |
Michael Forster | 6a184ad | 2021-10-12 13:04:05 +0000 | [diff] [blame] | 43 | #include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceLocation.h" |
Michael Forster | 028800b | 2021-10-05 12:39:59 +0000 | [diff] [blame] | 44 | #include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceManager.h" |
Googler | 2e85f34 | 2021-09-17 07:04:07 +0000 | [diff] [blame] | 45 | #include "third_party/llvm/llvm-project/clang/include/clang/Basic/Specifiers.h" |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 46 | #include "third_party/llvm/llvm-project/clang/include/clang/Sema/Sema.h" |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 47 | #include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Optional.h" |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 48 | #include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/SmallPtrSet.h" |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 49 | #include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Casting.h" |
Lukasz Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 50 | #include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Regex.h" |
Googler | 06f2c9a | 2022-01-05 12:00:47 +0000 | [diff] [blame] | 51 | #include "util/gtl/flat_map.h" |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 52 | |
| 53 | namespace rs_bindings_from_cc { |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 54 | namespace { |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 55 | |
Michael Forster | b836c58 | 2022-01-21 11:20:22 +0000 | [diff] [blame] | 56 | constexpr absl::string_view kTypeStatusPayloadUrl = |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 57 | "type.googleapis.com/devtools.rust.cc_interop.rs_binding_from_cc.type"; |
| 58 | |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 59 | // A mapping of C++ standard types to their equivalent Rust types. |
| 60 | // To produce more idiomatic results, these types receive special handling |
| 61 | // instead of using the generic type mapping mechanism. |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 62 | constexpr auto kWellKnownTypes = |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 63 | gtl::fixed_flat_map_of<absl::string_view, absl::string_view>({ |
| 64 | {"ptrdiff_t", "isize"}, |
| 65 | {"intptr_t", "isize"}, |
| 66 | {"size_t", "usize"}, |
| 67 | {"uintptr_t", "usize"}, |
Googler | 4e50488 | 2022-01-13 10:03:19 +0000 | [diff] [blame] | 68 | {"std::ptrdiff_t", "isize"}, |
| 69 | {"std::intptr_t", "isize"}, |
| 70 | {"std::size_t", "usize"}, |
| 71 | {"std::uintptr_t", "usize"}, |
| 72 | |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 73 | {"int8_t", "i8"}, |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 74 | {"int16_t", "i16"}, |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 75 | {"int32_t", "i32"}, |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 76 | {"int64_t", "i64"}, |
Googler | 4e50488 | 2022-01-13 10:03:19 +0000 | [diff] [blame] | 77 | {"std::int8_t", "i8"}, |
| 78 | {"std::int16_t", "i16"}, |
| 79 | {"std::int32_t", "i32"}, |
| 80 | {"std::int64_t", "i64"}, |
| 81 | |
| 82 | {"uint8_t", "u8"}, |
| 83 | {"uint16_t", "u16"}, |
| 84 | {"uint32_t", "u32"}, |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 85 | |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 86 | {"uint64_t", "u64"}, |
Googler | 4e50488 | 2022-01-13 10:03:19 +0000 | [diff] [blame] | 87 | {"std::uint8_t", "u8"}, |
| 88 | {"std::uint16_t", "u16"}, |
| 89 | {"std::uint32_t", "u32"}, |
| 90 | {"std::uint64_t", "u64"}, |
| 91 | |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 92 | {"char16_t", "u16"}, |
| 93 | {"char32_t", "u32"}, |
| 94 | {"wchar_t", "i32"}, |
| 95 | }); |
| 96 | |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 97 | DeclId GenerateDeclId(const clang::Decl* decl) { |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 98 | return DeclId(reinterpret_cast<uintptr_t>(decl->getCanonicalDecl())); |
| 99 | } |
| 100 | |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 101 | std::vector<BaseClass> GetUnambiguousPublicBases( |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 102 | const clang::CXXRecordDecl& record_decl, const clang::ASTContext& ctx) { |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 103 | // This function is unfortunate: the only way to correctly get information |
| 104 | // about the bases is lookupInBases. It runs a complex O(N^3) algorithm for |
| 105 | // e.g. correctly determining virtual base paths, etc. |
| 106 | // |
| 107 | // However, lookupInBases does not recurse into a class once it's found. |
| 108 | // So we need to call lookupInBases once per class, making this O(N^4). |
| 109 | |
| 110 | llvm::SmallPtrSet<const clang::CXXRecordDecl*, 4> seen; |
| 111 | std::vector<BaseClass> bases; |
| 112 | clang::CXXBasePaths paths; |
| 113 | // the const cast is a common pattern, apparently, see e.g. |
| 114 | // https://clang.llvm.org/doxygen/CXXInheritance_8cpp_source.html#l00074 |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 115 | paths.setOrigin(const_cast<clang::CXXRecordDecl*>(&record_decl)); |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 116 | |
| 117 | auto next_class = [&]() { |
| 118 | const clang::CXXRecordDecl* found = nullptr; |
| 119 | |
| 120 | // Matches the first new class it encounters (and adds it to `seen`, so |
| 121 | // that future runs don't rediscover it.) |
| 122 | auto is_new_class = [&](const clang::CXXBaseSpecifier* base_specifier, |
| 123 | clang::CXXBasePath&) { |
| 124 | const auto* record_decl = base_specifier->getType()->getAsCXXRecordDecl(); |
| 125 | if (found) { |
| 126 | return record_decl == found; |
| 127 | } |
| 128 | |
| 129 | if (record_decl && seen.insert(record_decl).second) { |
| 130 | found = record_decl; |
| 131 | return true; |
| 132 | } |
| 133 | return false; |
| 134 | }; |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 135 | return record_decl.lookupInBases(is_new_class, paths); |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 136 | }; |
| 137 | |
| 138 | for (; next_class(); paths.clear()) { |
| 139 | for (const clang::CXXBasePath& path : paths) { |
| 140 | if (path.Access != clang::AS_public) { |
| 141 | continue; |
| 142 | } |
| 143 | const clang::CXXBaseSpecifier& base_specifier = |
| 144 | *path[path.size() - 1].Base; |
| 145 | const clang::QualType& base = base_specifier.getType(); |
| 146 | if (paths.isAmbiguous(ctx.getCanonicalType(base))) { |
| 147 | continue; |
| 148 | } |
| 149 | const clang::CXXRecordDecl* base_record_decl = |
| 150 | ABSL_DIE_IF_NULL(base_specifier.getType()->getAsCXXRecordDecl()); |
| 151 | std::optional<int64_t> offset = {0}; |
| 152 | for (const clang::CXXBasePathElement& base_path_element : path) { |
| 153 | if (base_path_element.Base->isVirtual()) { |
| 154 | offset = std::nullopt; |
| 155 | break; |
| 156 | } |
| 157 | *offset += |
| 158 | {ctx.getASTRecordLayout(base_path_element.Class) |
| 159 | .getBaseClassOffset(ABSL_DIE_IF_NULL( |
| 160 | base_path_element.Base->getType()->getAsCXXRecordDecl())) |
| 161 | .getQuantity()}; |
| 162 | } |
| 163 | DCHECK(!offset.has_value() || *offset >= 0) |
| 164 | << "Concrete base classes should have non-negative offsets."; |
| 165 | bases.push_back( |
| 166 | BaseClass{.base_record_id = GenerateDeclId(base_record_decl), |
| 167 | .offset = offset}); |
| 168 | break; |
| 169 | } |
| 170 | } |
| 171 | return bases; |
| 172 | } |
| 173 | } // namespace |
| 174 | |
Michael Forster | 7b628b1 | 2022-01-27 17:48:57 +0000 | [diff] [blame] | 175 | std::vector<clang::RawComment*> Importer::ImportFreeComments() { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 176 | clang::SourceManager& sm = ctx_.getSourceManager(); |
Michael Forster | 7b628b1 | 2022-01-27 17:48:57 +0000 | [diff] [blame] | 177 | |
| 178 | // We put all comments into an ordered set in source order. Later we'll remove |
| 179 | // the comments that we don't want or that we get by other means. |
| 180 | auto source_order = [&sm](const clang::SourceLocation& a, |
| 181 | const clang::SourceLocation& b) { |
| 182 | return b.isValid() && (a.isInvalid() || sm.isBeforeInTranslationUnit(a, b)); |
| 183 | }; |
| 184 | auto ordered_comments = std::map<clang::SourceLocation, clang::RawComment*, |
| 185 | decltype(source_order)>(source_order); |
| 186 | |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 187 | // We start off by getting the comments from all entry header files... |
| 188 | for (const auto& header : invocation_.entry_headers_) { |
Michael Forster | 7b628b1 | 2022-01-27 17:48:57 +0000 | [diff] [blame] | 189 | if (auto file = sm.getFileManager().getFile(header.IncludePath())) { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 190 | if (auto comments = ctx_.Comments.getCommentsInFile( |
Michael Forster | 7b628b1 | 2022-01-27 17:48:57 +0000 | [diff] [blame] | 191 | sm.getOrCreateFileID(*file, clang::SrcMgr::C_User))) { |
| 192 | for (const auto& [_, comment] : *comments) { |
| 193 | ordered_comments.insert({comment->getBeginLoc(), comment}); |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | // ... and then we remove those that "conflict" with an IR item. |
| 200 | for (const auto& [decl, result] : lookup_cache_) { |
| 201 | if (result.item()) { |
| 202 | // Remove doc comments of imported items. |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 203 | if (auto raw_comment = ctx_.getRawCommentForDeclNoCache(decl)) { |
Michael Forster | 7b628b1 | 2022-01-27 17:48:57 +0000 | [diff] [blame] | 204 | ordered_comments.erase(raw_comment->getBeginLoc()); |
| 205 | } |
| 206 | // Remove comments that are within a visited decl. |
| 207 | // TODO(forster): We should retain floating comments in decls like |
| 208 | // records and namespaces. |
| 209 | ordered_comments.erase(ordered_comments.lower_bound(decl->getBeginLoc()), |
| 210 | ordered_comments.upper_bound(decl->getEndLoc())); |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | // Return the remaining comments as a `std::vector`. |
| 215 | std::vector<clang::RawComment*> result; |
| 216 | result.reserve(ordered_comments.size()); |
| 217 | for (auto& [_, comment] : ordered_comments) { |
| 218 | result.push_back(comment); |
| 219 | } |
| 220 | return result; |
| 221 | } |
| 222 | |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 223 | // Multiple IR items can be associated with the same source location (e.g. the |
| 224 | // implicitly defined constructors and assignment operators). To produce |
| 225 | // deterministic output, we order such items based on GetDeclOrder. The order |
| 226 | // is somewhat arbitrary, but we still try to make it aesthetically pleasing |
| 227 | // (e.g. constructors go before assignment operators; default constructor goes |
| 228 | // first, etc.). |
| 229 | static int GetDeclOrder(const clang::Decl* decl) { |
| 230 | if (clang::isa<clang::RecordDecl>(decl)) { |
| 231 | return decl->getDeclContext()->isRecord() ? 101 : 100; |
| 232 | } |
| 233 | |
| 234 | if (auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) { |
| 235 | return ctor->isDefaultConstructor() ? 202 |
| 236 | : ctor->isCopyConstructor() ? 203 |
| 237 | : ctor->isMoveConstructor() ? 204 |
| 238 | : 299; |
| 239 | } |
| 240 | |
| 241 | if (clang::isa<clang::CXXDestructorDecl>(decl)) { |
| 242 | return 306; |
| 243 | } |
| 244 | |
| 245 | if (auto* method = clang::dyn_cast<clang::CXXMethodDecl>(decl)) { |
| 246 | return method->isCopyAssignmentOperator() ? 401 |
| 247 | : method->isMoveAssignmentOperator() ? 402 |
| 248 | : 499; |
| 249 | } |
| 250 | |
| 251 | return 999; |
| 252 | } |
| 253 | |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 254 | void Importer::Import(clang::TranslationUnitDecl* translation_unit_decl) { |
| 255 | ImportDeclsFromDeclContext(translation_unit_decl); |
| 256 | |
Lukasz Anforowicz | bdf70d3 | 2022-01-26 19:06:21 +0000 | [diff] [blame] | 257 | using OrderedItem = std::tuple<clang::SourceRange, int, IR::Item>; |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 258 | clang::SourceManager& sm = ctx_.getSourceManager(); |
Lukasz Anforowicz | bdf70d3 | 2022-01-26 19:06:21 +0000 | [diff] [blame] | 259 | auto is_less_than = [&sm](const OrderedItem& a, const OrderedItem& b) { |
| 260 | auto a_range = std::get<0>(a); |
| 261 | auto b_range = std::get<0>(b); |
Lukasz Anforowicz | bdf70d3 | 2022-01-26 19:06:21 +0000 | [diff] [blame] | 262 | if (!a_range.isValid() || !b_range.isValid()) { |
| 263 | if (a_range.isValid() != b_range.isValid()) |
| 264 | return !a_range.isValid() && b_range.isValid(); |
| 265 | } else { |
| 266 | if (a_range.getBegin() != b_range.getBegin()) { |
| 267 | return sm.isBeforeInTranslationUnit(a_range.getBegin(), |
| 268 | b_range.getBegin()); |
| 269 | } |
| 270 | if (a_range.getEnd() != b_range.getEnd()) { |
| 271 | return sm.isBeforeInTranslationUnit(a_range.getEnd(), b_range.getEnd()); |
| 272 | } |
| 273 | } |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 274 | |
| 275 | auto a_decl_order = std::get<1>(a); |
| 276 | auto b_decl_order = std::get<1>(b); |
| 277 | if (a_decl_order != b_decl_order) return a_decl_order < b_decl_order; |
| 278 | |
| 279 | // A single FunctionDecl can be associated with multiple UnsupportedItems. |
| 280 | // Comparing the fields allows deterministic order between items like: |
| 281 | // Non-trivial_abi type '...' is not supported by value as a parameter. |
| 282 | // Non-trivial_abi type '...' is not supported by value as a return type. |
| 283 | const auto& a_variant = std::get<2>(a); |
| 284 | const auto& b_variant = std::get<2>(b); |
| 285 | const auto* a_unsupported = std::get_if<UnsupportedItem>(&a_variant); |
| 286 | const auto* b_unsupported = std::get_if<UnsupportedItem>(&b_variant); |
| 287 | if (a_unsupported && b_unsupported) { |
| 288 | if (a_unsupported->name != b_unsupported->name) |
| 289 | return a_unsupported->name < b_unsupported->name; |
| 290 | return a_unsupported->message < b_unsupported->message; |
| 291 | } |
| 292 | |
| 293 | return false; |
| 294 | }; |
| 295 | auto are_equal = [&is_less_than](const OrderedItem& a, const OrderedItem& b) { |
| 296 | return !is_less_than(a, b) && !is_less_than(b, a); |
Lukasz Anforowicz | bdf70d3 | 2022-01-26 19:06:21 +0000 | [diff] [blame] | 297 | }; |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 298 | |
| 299 | // We emit IR items in the order of the decls they were generated for. |
| 300 | // For decls that emit multiple items we use a stable, but arbitrary order. |
Lukasz Anforowicz | bdf70d3 | 2022-01-26 19:06:21 +0000 | [diff] [blame] | 301 | std::vector<OrderedItem> items; |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 302 | for (const auto& [decl, result] : lookup_cache_) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 303 | auto item = result.item(); |
| 304 | if (item) { |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 305 | items.push_back( |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 306 | std::make_tuple(decl->getSourceRange(), GetDeclOrder(decl), *item)); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 307 | } |
| 308 | if (IsFromCurrentTarget(decl)) { |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 309 | std::string name = "unnamed"; |
| 310 | if (const auto* named_decl = clang::dyn_cast<clang::NamedDecl>(decl)) { |
| 311 | name = named_decl->getQualifiedNameAsString(); |
| 312 | } |
| 313 | SourceLoc source_loc = ConvertSourceLocation(decl->getBeginLoc()); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 314 | for (const auto& error : result.errors()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 315 | items.push_back(std::make_tuple( |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 316 | decl->getSourceRange(), GetDeclOrder(decl), |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 317 | UnsupportedItem{ |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 318 | .name = name, .message = error, .source_loc = source_loc})); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 319 | } |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 320 | } |
| 321 | } |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 322 | |
Michael Forster | 7b628b1 | 2022-01-27 17:48:57 +0000 | [diff] [blame] | 323 | for (auto comment : ImportFreeComments()) { |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 324 | items.push_back(std::make_tuple( |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 325 | comment->getSourceRange(), 0 /* decl_order */, |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 326 | Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics())})); |
| 327 | } |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 328 | std::sort(items.begin(), items.end(), is_less_than); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 329 | |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 330 | for (size_t i = 0; i < items.size(); i++) { |
| 331 | const auto& item = items[i]; |
| 332 | if (i > 0) { |
| 333 | const auto& prev = items[i - 1]; |
| 334 | if (are_equal(item, prev)) { |
| 335 | std::string prev_json = |
| 336 | std::visit([&](auto&& item) { return item.ToJson().dump(); }, |
| 337 | std::get<2>(prev)); |
| 338 | std::string curr_json = |
| 339 | std::visit([&](auto&& item) { return item.ToJson().dump(); }, |
| 340 | std::get<2>(item)); |
| 341 | if (prev_json != curr_json) { |
| 342 | LOG(FATAL) << "Non-deterministic order of IR items: " << prev_json |
| 343 | << " -VS- " << curr_json; |
| 344 | } else { |
| 345 | // TODO(lukasza): Avoid generating duplicate IR items. Currently |
| 346 | // known example: UnsupportedItem: name=std::signbit; message= |
| 347 | // Items contained in namespaces are not supported yet. |
| 348 | LOG(WARNING) << "Duplicated IR item: " << curr_json; |
| 349 | continue; |
| 350 | } |
| 351 | } |
| 352 | } |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 353 | invocation_.ir_.items.push_back(std::get<2>(item)); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 354 | } |
| 355 | } |
| 356 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 357 | void Importer::ImportDeclsFromDeclContext( |
| 358 | const clang::DeclContext* decl_context) { |
| 359 | for (auto decl : decl_context->decls()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 360 | LookupDecl(decl->getCanonicalDecl()); |
| 361 | |
| 362 | if (auto* nested_context = clang::dyn_cast<clang::DeclContext>(decl)) { |
| 363 | if (nested_context->isNamespace()) |
| 364 | ImportDeclsFromDeclContext(nested_context); |
| 365 | } |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | Importer::LookupResult Importer::LookupDecl(clang::Decl* decl) { |
| 370 | if (!lookup_cache_.contains(decl)) { |
| 371 | lookup_cache_.insert({decl, ImportDecl(decl)}); |
| 372 | } |
| 373 | |
| 374 | return lookup_cache_[decl]; |
| 375 | } |
| 376 | |
| 377 | Importer::LookupResult Importer::ImportDecl(clang::Decl* decl) { |
| 378 | if (decl->getDeclContext()->isNamespace()) { |
| 379 | return LookupResult("Items contained in namespaces are not supported yet"); |
| 380 | } |
| 381 | |
| 382 | if (auto* function_decl = clang::dyn_cast<clang::FunctionDecl>(decl)) { |
| 383 | return ImportFunction(function_decl); |
| 384 | } else if (auto* function_template_decl = |
| 385 | clang::dyn_cast<clang::FunctionTemplateDecl>(decl)) { |
| 386 | return ImportFunction(function_template_decl->getTemplatedDecl()); |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 387 | } else if (auto* record_decl = clang::dyn_cast<clang::CXXRecordDecl>(decl)) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 388 | auto result = ImportRecord(record_decl); |
| 389 | // TODO(forster): Should we even visit the nested decl if we couldn't |
| 390 | // import the parent? For now we have tests that check that we generate |
| 391 | // error messages for those decls, so we're visiting. |
| 392 | ImportDeclsFromDeclContext(record_decl); |
| 393 | return result; |
| 394 | } else if (auto* typedef_name_decl = |
| 395 | clang::dyn_cast<clang::TypedefNameDecl>(decl)) { |
| 396 | return ImportTypedefName(typedef_name_decl); |
| 397 | } else if (clang::isa<clang::ClassTemplateDecl>(decl)) { |
| 398 | return LookupResult("Class templates are not supported yet"); |
| 399 | } else { |
| 400 | return LookupResult(); |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | Importer::LookupResult Importer::ImportFunction( |
| 405 | clang::FunctionDecl* function_decl) { |
| 406 | if (!IsFromCurrentTarget(function_decl)) return LookupResult(); |
| 407 | if (function_decl->isDeleted()) return LookupResult(); |
Marcel Hlopko | 3df195b | 2022-01-26 14:15:03 +0000 | [diff] [blame] | 408 | if (function_decl->isTemplated()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 409 | return LookupResult("Function templates are not supported yet"); |
Marcel Hlopko | 3df195b | 2022-01-26 14:15:03 +0000 | [diff] [blame] | 410 | } |
Marcel Hlopko | 36ced2d | 2021-12-02 10:47:37 +0000 | [diff] [blame] | 411 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 412 | devtools_rust::LifetimeSymbolTable lifetime_symbol_table; |
| 413 | llvm::Expected<devtools_rust::FunctionLifetimes> lifetimes = |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 414 | devtools_rust::GetLifetimeAnnotations(function_decl, |
| 415 | *invocation_.lifetime_context_, |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 416 | &lifetime_symbol_table); |
| 417 | llvm::DenseSet<devtools_rust::Lifetime> all_lifetimes; |
| 418 | |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 419 | std::vector<FuncParam> params; |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 420 | std::set<std::string> errors; |
| 421 | auto add_error = [&errors, function_decl](std::string msg) { |
| 422 | auto result = errors.insert(std::move(msg)); |
| 423 | CHECK(result.second) << "Duplicated error message for " |
| 424 | << function_decl->getNameAsString() << ": " |
| 425 | << *result.first; |
| 426 | }; |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 427 | if (auto* method_decl = |
| 428 | clang::dyn_cast<clang::CXXMethodDecl>(function_decl)) { |
Marcel Hlopko | a5a1873 | 2022-01-27 09:58:53 +0000 | [diff] [blame] | 429 | if (!known_type_decls_.contains( |
| 430 | method_decl->getParent()->getCanonicalDecl())) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 431 | return LookupResult("Couldn't import the parent"); |
Marcel Hlopko | a5a1873 | 2022-01-27 09:58:53 +0000 | [diff] [blame] | 432 | } |
| 433 | |
| 434 | // non-static member functions receive an implicit `this` parameter. |
Devin Jeanpierre | d4dde0e | 2021-10-13 20:48:25 +0000 | [diff] [blame] | 435 | if (method_decl->isInstance()) { |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 436 | std::optional<devtools_rust::TypeLifetimes> this_lifetimes; |
| 437 | if (lifetimes) { |
| 438 | this_lifetimes = lifetimes->this_lifetimes; |
| 439 | all_lifetimes.insert(this_lifetimes->begin(), this_lifetimes->end()); |
| 440 | } |
| 441 | auto param_type = ConvertType(method_decl->getThisType(), this_lifetimes, |
| 442 | /*nullable=*/false); |
Devin Jeanpierre | d4dde0e | 2021-10-13 20:48:25 +0000 | [diff] [blame] | 443 | if (!param_type.ok()) { |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 444 | add_error(absl::StrCat("`this` parameter is not supported: ", |
| 445 | param_type.status().message())); |
Devin Jeanpierre | fecf547 | 2021-10-27 10:52:30 +0000 | [diff] [blame] | 446 | } else { |
| 447 | params.push_back({*std::move(param_type), Identifier("__this")}); |
Devin Jeanpierre | d4dde0e | 2021-10-13 20:48:25 +0000 | [diff] [blame] | 448 | } |
Devin Jeanpierre | d4dde0e | 2021-10-13 20:48:25 +0000 | [diff] [blame] | 449 | } |
| 450 | } |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 451 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 452 | if (lifetimes) { |
| 453 | CHECK_EQ(lifetimes->param_lifetimes.size(), function_decl->getNumParams()); |
| 454 | } |
| 455 | for (unsigned i = 0; i < function_decl->getNumParams(); ++i) { |
| 456 | const clang::ParmVarDecl* param = function_decl->getParamDecl(i); |
| 457 | std::optional<devtools_rust::TypeLifetimes> param_lifetimes; |
| 458 | if (lifetimes) { |
| 459 | param_lifetimes = lifetimes->param_lifetimes[i]; |
| 460 | all_lifetimes.insert(param_lifetimes->begin(), param_lifetimes->end()); |
| 461 | } |
| 462 | auto param_type = ConvertType(param->getType(), param_lifetimes); |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 463 | if (!param_type.ok()) { |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 464 | add_error(absl::Substitute("Parameter #$0 is not supported: $1", i, |
| 465 | param_type.status().message())); |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 466 | continue; |
Michael Forster | 1de27b8 | 2021-09-17 07:22:22 +0000 | [diff] [blame] | 467 | } |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 468 | |
| 469 | if (const clang::RecordType* record_type = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 470 | clang::dyn_cast<clang::RecordType>(param->getType())) { |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 471 | if (clang::RecordDecl* record_decl = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 472 | clang::dyn_cast<clang::RecordDecl>(record_type->getDecl())) { |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 473 | // TODO(b/200067242): non-trivial_abi structs, when passed by value, |
| 474 | // have a different representation which needs special support. We |
| 475 | // currently do not support it. |
| 476 | if (!record_decl->canPassInRegisters()) { |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 477 | add_error( |
Marcel Hlopko | 3df7254 | 2021-11-30 09:38:36 +0000 | [diff] [blame] | 478 | absl::Substitute("Non-trivial_abi type '$0' is not " |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 479 | "supported by value as parameter #$1", |
| 480 | param->getType().getAsString(), i)); |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 481 | } |
| 482 | } |
| 483 | } |
| 484 | |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 485 | std::optional<Identifier> param_name = GetTranslatedIdentifier(param); |
Lukasz Anforowicz | 0c816f1 | 2021-12-15 17:41:49 +0000 | [diff] [blame] | 486 | CHECK(param_name.has_value()); // No known cases where the above can fail. |
Devin Jeanpierre | e78b2fb | 2021-10-05 11:40:33 +0000 | [diff] [blame] | 487 | params.push_back({*param_type, *std::move(param_name)}); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 488 | } |
| 489 | |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 490 | if (const clang::RecordType* record_return_type = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 491 | clang::dyn_cast<clang::RecordType>(function_decl->getReturnType())) { |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 492 | if (clang::RecordDecl* record_decl = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 493 | clang::dyn_cast<clang::RecordDecl>(record_return_type->getDecl())) { |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 494 | // TODO(b/200067242): non-trivial_abi structs, when passed by value, |
| 495 | // have a different representation which needs special support. We |
| 496 | // currently do not support it. |
| 497 | if (!record_decl->canPassInRegisters()) { |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 498 | add_error( |
Marcel Hlopko | 3df7254 | 2021-11-30 09:38:36 +0000 | [diff] [blame] | 499 | absl::Substitute("Non-trivial_abi type '$0' is not supported " |
| 500 | "by value as a return type", |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 501 | function_decl->getReturnType().getAsString())); |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 502 | } |
| 503 | } |
| 504 | } |
| 505 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 506 | std::optional<devtools_rust::TypeLifetimes> return_lifetimes; |
| 507 | if (lifetimes) { |
| 508 | return_lifetimes = lifetimes->return_lifetimes; |
| 509 | all_lifetimes.insert(return_lifetimes->begin(), return_lifetimes->end()); |
| 510 | } |
| 511 | auto return_type = |
| 512 | ConvertType(function_decl->getReturnType(), return_lifetimes); |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 513 | if (!return_type.ok()) { |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 514 | add_error(absl::StrCat("Return type is not supported: ", |
| 515 | return_type.status().message())); |
Michael Forster | 1de27b8 | 2021-09-17 07:22:22 +0000 | [diff] [blame] | 516 | } |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 517 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 518 | std::vector<Lifetime> lifetime_params; |
| 519 | for (devtools_rust::Lifetime lifetime : all_lifetimes) { |
| 520 | std::optional<llvm::StringRef> name = |
| 521 | lifetime_symbol_table.LookupLifetime(lifetime); |
| 522 | CHECK(name.has_value()); |
| 523 | lifetime_params.push_back( |
| 524 | {.name = name->str(), .id = LifetimeId(lifetime.Id())}); |
| 525 | } |
| 526 | std::sort( |
| 527 | lifetime_params.begin(), lifetime_params.end(), |
| 528 | [](const Lifetime& l1, const Lifetime& l2) { return l1.name < l2.name; }); |
| 529 | |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 530 | std::optional<MemberFuncMetadata> member_func_metadata; |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 531 | if (auto* method_decl = |
| 532 | clang::dyn_cast<clang::CXXMethodDecl>(function_decl)) { |
Lukasz Anforowicz | 57331cf | 2021-12-16 02:57:19 +0000 | [diff] [blame] | 533 | switch (method_decl->getAccess()) { |
| 534 | case clang::AS_public: |
| 535 | break; |
| 536 | case clang::AS_protected: |
| 537 | case clang::AS_private: |
| 538 | case clang::AS_none: |
| 539 | // No need for IR to include Func representing private methods. |
| 540 | // TODO(lukasza): Revisit this for protected methods. |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 541 | return LookupResult(); |
Lukasz Anforowicz | 57331cf | 2021-12-16 02:57:19 +0000 | [diff] [blame] | 542 | } |
Devin Jeanpierre | 96839c1 | 2021-12-14 00:27:38 +0000 | [diff] [blame] | 543 | std::optional<MemberFuncMetadata::InstanceMethodMetadata> instance_metadata; |
| 544 | if (method_decl->isInstance()) { |
| 545 | MemberFuncMetadata::ReferenceQualification reference; |
| 546 | switch (method_decl->getRefQualifier()) { |
| 547 | case clang::RQ_LValue: |
| 548 | reference = MemberFuncMetadata::kLValue; |
| 549 | break; |
| 550 | case clang::RQ_RValue: |
| 551 | reference = MemberFuncMetadata::kRValue; |
| 552 | break; |
| 553 | case clang::RQ_None: |
| 554 | reference = MemberFuncMetadata::kUnqualified; |
| 555 | break; |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 556 | } |
Devin Jeanpierre | 96839c1 | 2021-12-14 00:27:38 +0000 | [diff] [blame] | 557 | instance_metadata = MemberFuncMetadata::InstanceMethodMetadata{ |
| 558 | .reference = reference, |
| 559 | .is_const = method_decl->isConst(), |
| 560 | .is_virtual = method_decl->isVirtual(), |
Lukasz Anforowicz | 71716b7 | 2022-01-26 17:05:05 +0000 | [diff] [blame] | 561 | .is_explicit_ctor = false, |
Devin Jeanpierre | 96839c1 | 2021-12-14 00:27:38 +0000 | [diff] [blame] | 562 | }; |
Lukasz Anforowicz | 71716b7 | 2022-01-26 17:05:05 +0000 | [diff] [blame] | 563 | if (auto* ctor_decl = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 564 | clang::dyn_cast<clang::CXXConstructorDecl>(function_decl)) { |
Lukasz Anforowicz | 71716b7 | 2022-01-26 17:05:05 +0000 | [diff] [blame] | 565 | instance_metadata->is_explicit_ctor = ctor_decl->isExplicit(); |
| 566 | } |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 567 | } |
Devin Jeanpierre | 96839c1 | 2021-12-14 00:27:38 +0000 | [diff] [blame] | 568 | |
| 569 | member_func_metadata = MemberFuncMetadata{ |
| 570 | .record_id = GenerateDeclId(method_decl->getParent()), |
| 571 | .instance_method_metadata = instance_metadata}; |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 572 | } |
| 573 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 574 | if (!errors.empty()) { |
| 575 | return LookupResult(errors); |
| 576 | } |
| 577 | |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 578 | std::optional<UnqualifiedIdentifier> translated_name = |
| 579 | GetTranslatedName(function_decl); |
Michael Forster | 277ff95 | 2022-01-27 18:14:56 +0000 | [diff] [blame] | 580 | CHECK(return_type.ok()); // Silence ClangTidy, checked above. |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 581 | if (translated_name.has_value()) { |
| 582 | return LookupResult(Func{ |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 583 | .name = *translated_name, |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 584 | .owning_target = GetOwningTarget(function_decl), |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 585 | .doc_comment = GetComment(function_decl), |
| 586 | .mangled_name = GetMangledName(function_decl), |
| 587 | .return_type = *return_type, |
| 588 | .params = std::move(params), |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 589 | .lifetime_params = std::move(lifetime_params), |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 590 | .is_inline = function_decl->isInlined(), |
Devin Jeanpierre | c6877bb | 2021-10-13 20:47:54 +0000 | [diff] [blame] | 591 | .member_func_metadata = std::move(member_func_metadata), |
Googler | 95f29a1 | 2022-01-07 07:47:26 +0000 | [diff] [blame] | 592 | .source_loc = ConvertSourceLocation(function_decl->getBeginLoc()), |
Michael Forster | 523dbd4 | 2021-10-12 11:05:44 +0000 | [diff] [blame] | 593 | }); |
Devin Jeanpierre | e78b2fb | 2021-10-05 11:40:33 +0000 | [diff] [blame] | 594 | } |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 595 | return LookupResult(); |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 596 | } |
| 597 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 598 | BlazeLabel Importer::GetOwningTarget(const clang::Decl* decl) const { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 599 | clang::SourceManager& source_manager = ctx_.getSourceManager(); |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 600 | auto source_location = decl->getLocation(); |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 601 | |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 602 | // If the header this decl comes from is not associated with a target we |
| 603 | // consider it a textual header. In that case we go up the include stack |
| 604 | // until we find a header that has an owning target. |
| 605 | |
Rosica Dejanovska | 381d103 | 2022-02-03 22:19:54 +0000 | [diff] [blame] | 606 | while (source_location.isValid()) { |
Rosica Dejanovska | 503d7dd | 2022-02-01 20:37:49 +0000 | [diff] [blame] | 607 | if (source_location.isMacroID()) { |
| 608 | source_location = source_manager.getExpansionLoc(source_location); |
| 609 | } |
| 610 | auto id = source_manager.getFileID(source_location); |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 611 | llvm::Optional<llvm::StringRef> filename = |
| 612 | source_manager.getNonBuiltinFilenameForID(id); |
| 613 | if (!filename) { |
| 614 | return BlazeLabel("//:builtin"); |
| 615 | } |
| 616 | if (filename->startswith("./")) { |
| 617 | filename = filename->substr(2); |
| 618 | } |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 619 | |
| 620 | if (auto target = invocation_.header_target(HeaderName(filename->str()))) { |
| 621 | return *target; |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 622 | } |
| 623 | source_location = source_manager.getIncludeLoc(id); |
Marcel Hlopko | 4c660dd | 2021-12-02 09:52:47 +0000 | [diff] [blame] | 624 | } |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 625 | |
| 626 | return BlazeLabel("//:virtual_clang_resource_dir_target"); |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 627 | } |
| 628 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 629 | bool Importer::IsFromCurrentTarget(const clang::Decl* decl) const { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 630 | return invocation_.target_ == GetOwningTarget(decl); |
Marcel Hlopko | 4c660dd | 2021-12-02 09:52:47 +0000 | [diff] [blame] | 631 | } |
| 632 | |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 633 | Importer::LookupResult Importer::ImportRecord( |
| 634 | clang::CXXRecordDecl* record_decl) { |
Googler | 21351fc | 2021-10-19 08:58:04 +0000 | [diff] [blame] | 635 | const clang::DeclContext* decl_context = record_decl->getDeclContext(); |
Dmitri Gribenko | 1462769 | 2022-01-31 09:37:00 +0000 | [diff] [blame] | 636 | if (decl_context->isFunctionOrMethod()) { |
| 637 | return LookupResult(); |
| 638 | } |
| 639 | if (record_decl->isInjectedClassName()) { |
| 640 | return LookupResult(); |
Googler | 21351fc | 2021-10-19 08:58:04 +0000 | [diff] [blame] | 641 | } |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 642 | if (decl_context->isRecord()) { |
| 643 | return LookupResult("Nested classes are not supported yet"); |
| 644 | } |
Marcel Hlopko | 872df5e | 2022-01-25 21:18:55 +0000 | [diff] [blame] | 645 | if (record_decl->isUnion()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 646 | return LookupResult("Unions are not supported yet"); |
Marcel Hlopko | 872df5e | 2022-01-25 21:18:55 +0000 | [diff] [blame] | 647 | } |
Googler | 8173f59 | 2022-01-04 13:57:32 +0000 | [diff] [blame] | 648 | // Make sure the record has a definition that we'll be able to call |
| 649 | // ASTContext::getASTRecordLayout() on. |
| 650 | record_decl = record_decl->getDefinition(); |
| 651 | if (!record_decl || record_decl->isInvalidDecl() || |
| 652 | !record_decl->isCompleteDefinition()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 653 | return LookupResult(); |
Googler | 8173f59 | 2022-01-04 13:57:32 +0000 | [diff] [blame] | 654 | } |
| 655 | |
Devin Jeanpierre | c80e624 | 2022-02-03 01:56:40 +0000 | [diff] [blame] | 656 | // To compute the memory layout of the record, it needs to be a concrete type, |
| 657 | // not a template. |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 658 | if (record_decl->getDescribedClassTemplate() || |
| 659 | clang::isa<clang::ClassTemplateSpecializationDecl>(record_decl)) { |
Devin Jeanpierre | c80e624 | 2022-02-03 01:56:40 +0000 | [diff] [blame] | 660 | return LookupResult("Class templates are not supported yet"); |
| 661 | } |
| 662 | |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 663 | sema_.ForceDeclarationOfImplicitMembers(record_decl); |
| 664 | |
Devin Jeanpierre | c80e624 | 2022-02-03 01:56:40 +0000 | [diff] [blame] | 665 | const clang::ASTRecordLayout& layout = ctx_.getASTRecordLayout(record_decl); |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 666 | |
Devin Jeanpierre | c80e624 | 2022-02-03 01:56:40 +0000 | [diff] [blame] | 667 | std::optional<size_t> base_size = std::nullopt; |
| 668 | bool override_alignment = false; |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 669 | if (record_decl->getNumBases() != 0) { |
| 670 | // The size of the base class subobjects is easy to compute, so long as we |
| 671 | // know that fields start after the base class subobjects. (This is not |
| 672 | // guaranteed by the standard, but is true on the ABIs we work with.) |
| 673 | base_size = layout.getFieldCount() == 0 |
| 674 | ? static_cast<size_t>(layout.getDataSize().getQuantity()) |
| 675 | : layout.getFieldOffset(0) / 8; |
| 676 | // Ideally, we'd only include an alignment adjustment if one of the base |
| 677 | // classes is more-aligned than any of the fields, but it is simpler do it |
| 678 | // whenever there are any base classes at all. |
| 679 | override_alignment = true; |
Googler | 2e85f34 | 2021-09-17 07:04:07 +0000 | [diff] [blame] | 680 | } |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 681 | |
Googler | 279eca3 | 2022-01-04 14:03:44 +0000 | [diff] [blame] | 682 | std::optional<Identifier> record_name = GetTranslatedIdentifier(record_decl); |
| 683 | if (!record_name.has_value()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 684 | return LookupResult(); |
Googler | 279eca3 | 2022-01-04 14:03:44 +0000 | [diff] [blame] | 685 | } |
| 686 | // Provisionally assume that we know this RecordDecl so that we'll be able |
| 687 | // to import fields whose type contains the record itself. |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 688 | known_type_decls_.insert(record_decl); |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 689 | absl::StatusOr<std::vector<Field>> fields = ImportFields(record_decl); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 690 | if (!fields.ok()) { |
Googler | 279eca3 | 2022-01-04 14:03:44 +0000 | [diff] [blame] | 691 | // Importing a field failed, so note that we didn't import this RecordDecl |
| 692 | // after all. |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 693 | known_type_decls_.erase(record_decl); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 694 | return LookupResult("Importing field failed"); |
Devin Jeanpierre | e78b2fb | 2021-10-05 11:40:33 +0000 | [diff] [blame] | 695 | } |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 696 | |
Devin Jeanpierre | b69bcae | 2022-02-03 09:45:50 +0000 | [diff] [blame] | 697 | for (const Field& field : *fields) { |
| 698 | if (field.is_no_unique_address) { |
| 699 | override_alignment = true; |
| 700 | break; |
| 701 | } |
| 702 | } |
| 703 | |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 704 | return LookupResult(Record{ |
| 705 | .identifier = *record_name, |
| 706 | .id = GenerateDeclId(record_decl), |
| 707 | .owning_target = GetOwningTarget(record_decl), |
| 708 | .doc_comment = GetComment(record_decl), |
| 709 | .unambiguous_public_bases = GetUnambiguousPublicBases(*record_decl, ctx_), |
| 710 | .fields = *std::move(fields), |
| 711 | .size = layout.getSize().getQuantity(), |
| 712 | .alignment = layout.getAlignment().getQuantity(), |
| 713 | .base_size = base_size, |
| 714 | .override_alignment = override_alignment, |
| 715 | .copy_constructor = GetCopyCtorSpecialMemberFunc(*record_decl), |
| 716 | .move_constructor = GetMoveCtorSpecialMemberFunc(*record_decl), |
| 717 | .destructor = GetDestructorSpecialMemberFunc(*record_decl), |
| 718 | .is_trivial_abi = record_decl->canPassInRegisters(), |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 719 | .is_final = record_decl->isEffectivelyFinal()}); |
Marcel Hlopko | b4b2874 | 2021-09-15 12:45:20 +0000 | [diff] [blame] | 720 | } |
| 721 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 722 | Importer::LookupResult Importer::ImportTypedefName( |
Googler | 6834699 | 2022-01-05 06:11:31 +0000 | [diff] [blame] | 723 | clang::TypedefNameDecl* typedef_name_decl) { |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 724 | const clang::DeclContext* decl_context = typedef_name_decl->getDeclContext(); |
| 725 | if (decl_context) { |
| 726 | if (decl_context->isFunctionOrMethod()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 727 | return LookupResult(); |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 728 | } |
| 729 | if (decl_context->isRecord()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 730 | return LookupResult("Typedefs nested in classes are not supported yet"); |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 731 | } |
| 732 | } |
| 733 | |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 734 | clang::QualType type = |
| 735 | typedef_name_decl->getASTContext().getTypedefType(typedef_name_decl); |
| 736 | if (kWellKnownTypes.contains(type.getAsString())) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 737 | return LookupResult(); |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 738 | } |
| 739 | |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 740 | std::optional<Identifier> identifier = |
| 741 | GetTranslatedIdentifier(typedef_name_decl); |
| 742 | if (!identifier.has_value()) { |
| 743 | // This should never happen. |
| 744 | LOG(FATAL) << "Couldn't get identifier for TypedefNameDecl"; |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 745 | } |
| 746 | absl::StatusOr<MappedType> underlying_type = |
| 747 | ConvertType(typedef_name_decl->getUnderlyingType()); |
| 748 | if (underlying_type.ok()) { |
| 749 | known_type_decls_.insert(typedef_name_decl); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 750 | return LookupResult( |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 751 | TypeAlias{.identifier = *identifier, |
| 752 | .id = GenerateDeclId(typedef_name_decl), |
| 753 | .owning_target = GetOwningTarget(typedef_name_decl), |
| 754 | .underlying_type = *underlying_type}); |
| 755 | } else { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 756 | return LookupResult(std::string(underlying_type.status().message())); |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 757 | } |
Googler | 6834699 | 2022-01-05 06:11:31 +0000 | [diff] [blame] | 758 | } |
| 759 | |
Lukasz Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 760 | static bool ShouldKeepCommentLine(absl::string_view line) { |
| 761 | // Based on https://clang.llvm.org/extra/clang-tidy/: |
| 762 | llvm::Regex patterns_to_ignore( |
| 763 | "^[[:space:]/]*" // Whitespace, or extra // |
| 764 | "(NOLINT|NOLINTNEXTLINE|NOLINTBEGIN|NOLINTEND)" |
| 765 | "(\\([^)[:space:]]*\\)?)?" // Optional (...) |
| 766 | "[[:space:]]*$"); // Whitespace |
| 767 | return !patterns_to_ignore.match(line); |
| 768 | } |
| 769 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 770 | std::optional<std::string> Importer::GetComment(const clang::Decl* decl) const { |
Michael Forster | 409d941 | 2021-10-07 08:35:29 +0000 | [diff] [blame] | 771 | // This does currently not distinguish between different types of comments. |
| 772 | // In general it is not possible in C++ to reliably only extract doc comments. |
| 773 | // This is going to be a heuristic that needs to be tuned over time. |
| 774 | |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 775 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 776 | clang::RawComment* raw_comment = ctx_.getRawCommentForDeclNoCache(decl); |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 777 | |
| 778 | if (raw_comment == nullptr) { |
| 779 | return {}; |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 780 | } |
Lukasz Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 781 | |
| 782 | std::string raw_comment_text = |
| 783 | raw_comment->getFormattedText(sm, sm.getDiagnostics()); |
| 784 | std::string cleaned_comment_text = absl::StrJoin( |
| 785 | absl::StrSplit(raw_comment_text, '\n', ShouldKeepCommentLine), "\n"); |
| 786 | return cleaned_comment_text.empty() |
| 787 | ? std::nullopt |
| 788 | : std::optional<std::string>(std::move(cleaned_comment_text)); |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 789 | } |
| 790 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 791 | SourceLoc Importer::ConvertSourceLocation(clang::SourceLocation loc) const { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 792 | auto& sm = ctx_.getSourceManager(); |
Michael Forster | d3ef1e9 | 2021-10-12 16:15:31 +0000 | [diff] [blame] | 793 | |
Googler | c8a8e73 | 2021-10-19 07:49:24 +0000 | [diff] [blame] | 794 | clang::StringRef filename = sm.getFilename(loc); |
Michael Forster | d3ef1e9 | 2021-10-12 16:15:31 +0000 | [diff] [blame] | 795 | if (filename.startswith("./")) { |
| 796 | filename = filename.substr(2); |
| 797 | } |
| 798 | |
| 799 | return SourceLoc{.filename = filename.str(), |
| 800 | .line = sm.getSpellingLineNumber(loc), |
| 801 | .column = sm.getSpellingColumnNumber(loc)}; |
| 802 | } |
| 803 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 804 | absl::StatusOr<MappedType> Importer::ConvertType( |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 805 | clang::QualType qual_type, |
| 806 | std::optional<devtools_rust::TypeLifetimes> lifetimes, |
| 807 | bool nullable) const { |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 808 | std::optional<MappedType> type = std::nullopt; |
Googler | db11153 | 2022-01-05 06:12:13 +0000 | [diff] [blame] | 809 | // When converting the type to a string, don't include qualifiers -- we handle |
| 810 | // these separately. |
| 811 | std::string type_string = qual_type.getUnqualifiedType().getAsString(); |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 812 | |
Googler | 44e3fbc | 2022-01-11 10:19:26 +0000 | [diff] [blame] | 813 | if (auto iter = kWellKnownTypes.find(type_string); |
| 814 | iter != kWellKnownTypes.end()) { |
Googler | 06f2c9a | 2022-01-05 12:00:47 +0000 | [diff] [blame] | 815 | type = MappedType::Simple(std::string(iter->second), type_string); |
| 816 | } else if (const auto* pointer_type = |
| 817 | qual_type->getAs<clang::PointerType>()) { |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 818 | std::optional<LifetimeId> lifetime; |
| 819 | if (lifetimes.has_value()) { |
| 820 | CHECK(!lifetimes->empty()); |
| 821 | lifetime = LifetimeId(lifetimes->back().Id()); |
| 822 | lifetimes->pop_back(); |
| 823 | } |
| 824 | auto pointee_type = ConvertType(pointer_type->getPointeeType(), lifetimes); |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 825 | if (pointee_type.ok()) { |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 826 | type = MappedType::PointerTo(*pointee_type, lifetime, nullable); |
Michael Forster | 1de27b8 | 2021-09-17 07:22:22 +0000 | [diff] [blame] | 827 | } |
Googler | 61dce3b | 2021-12-02 09:16:32 +0000 | [diff] [blame] | 828 | } else if (const auto* lvalue_ref_type = |
| 829 | qual_type->getAs<clang::LValueReferenceType>()) { |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 830 | std::optional<LifetimeId> lifetime; |
| 831 | if (lifetimes.has_value()) { |
| 832 | CHECK(!lifetimes->empty()); |
| 833 | lifetime = LifetimeId(lifetimes->back().Id()); |
| 834 | lifetimes->pop_back(); |
| 835 | } |
| 836 | auto pointee_type = |
| 837 | ConvertType(lvalue_ref_type->getPointeeType(), lifetimes); |
Googler | 61dce3b | 2021-12-02 09:16:32 +0000 | [diff] [blame] | 838 | if (pointee_type.ok()) { |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 839 | type = MappedType::LValueReferenceTo(*pointee_type, lifetime); |
Googler | 61dce3b | 2021-12-02 09:16:32 +0000 | [diff] [blame] | 840 | } |
Googler | b6c0fe0 | 2021-12-01 10:55:31 +0000 | [diff] [blame] | 841 | } else if (const auto* builtin_type = |
Googler | 06f2c9a | 2022-01-05 12:00:47 +0000 | [diff] [blame] | 842 | // Use getAsAdjusted instead of getAs so we don't desugar |
| 843 | // typedefs. |
| 844 | qual_type->getAsAdjusted<clang::BuiltinType>()) { |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 845 | switch (builtin_type->getKind()) { |
| 846 | case clang::BuiltinType::Bool: |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 847 | type = MappedType::Simple("bool", "bool"); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 848 | break; |
| 849 | case clang::BuiltinType::Float: |
Michael Forster | c7976ec | 2021-10-01 10:05:16 +0000 | [diff] [blame] | 850 | type = MappedType::Simple("f32", "float"); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 851 | break; |
| 852 | case clang::BuiltinType::Double: |
Michael Forster | c7976ec | 2021-10-01 10:05:16 +0000 | [diff] [blame] | 853 | type = MappedType::Simple("f64", "double"); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 854 | break; |
| 855 | case clang::BuiltinType::Void: |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 856 | type = MappedType::Void(); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 857 | break; |
| 858 | default: |
| 859 | if (builtin_type->isIntegerType()) { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 860 | auto size = ctx_.getTypeSize(builtin_type); |
Googler | 06f2c9a | 2022-01-05 12:00:47 +0000 | [diff] [blame] | 861 | if (size == 8 || size == 16 || size == 32 || size == 64) { |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 862 | type = MappedType::Simple( |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 863 | absl::Substitute( |
| 864 | "$0$1", builtin_type->isSignedInteger() ? 'i' : 'u', size), |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 865 | type_string); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 866 | } |
| 867 | } |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 868 | } |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 869 | } else if (const auto* tag_type = |
Googler | 6a0a525 | 2022-01-11 14:08:09 +0000 | [diff] [blame] | 870 | qual_type->getAsAdjusted<clang::TagType>()) { |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 871 | clang::TagDecl* tag_decl = tag_type->getDecl(); |
| 872 | |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 873 | if (known_type_decls_.contains(tag_decl)) { |
Googler | 279eca3 | 2022-01-04 14:03:44 +0000 | [diff] [blame] | 874 | if (std::optional<Identifier> id = GetTranslatedIdentifier(tag_decl)) { |
| 875 | std::string ident(id->Ident()); |
| 876 | DeclId decl_id = GenerateDeclId(tag_decl); |
| 877 | type = MappedType::WithDeclIds(ident, decl_id, ident, decl_id); |
| 878 | } |
Devin Jeanpierre | bf0d560 | 2021-10-13 20:47:39 +0000 | [diff] [blame] | 879 | } |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 880 | } else if (const auto* typedef_type = |
Googler | 6a0a525 | 2022-01-11 14:08:09 +0000 | [diff] [blame] | 881 | qual_type->getAsAdjusted<clang::TypedefType>()) { |
Googler | dcca7f7 | 2022-01-10 12:30:43 +0000 | [diff] [blame] | 882 | clang::TypedefNameDecl* typedef_name_decl = typedef_type->getDecl(); |
| 883 | |
| 884 | if (known_type_decls_.contains(typedef_name_decl)) { |
| 885 | if (std::optional<Identifier> id = |
| 886 | GetTranslatedIdentifier(typedef_name_decl)) { |
| 887 | std::string ident(id->Ident()); |
| 888 | DeclId decl_id = GenerateDeclId(typedef_name_decl); |
| 889 | type = MappedType::WithDeclIds(ident, decl_id, ident, decl_id); |
| 890 | } |
| 891 | } |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 892 | } |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 893 | |
| 894 | if (!type.has_value()) { |
| 895 | absl::Status error = absl::UnimplementedError( |
| 896 | absl::Substitute("Unsupported type '$0'", type_string)); |
| 897 | error.SetPayload(kTypeStatusPayloadUrl, absl::Cord(type_string)); |
| 898 | return error; |
| 899 | } |
| 900 | |
| 901 | // Add cv-qualification. |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 902 | type->cc_type.is_const = qual_type.isConstQualified(); |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 903 | // Not doing volatile for now -- note that volatile pointers do not exist in |
| 904 | // Rust, though volatile reads/writes still do. |
| 905 | |
| 906 | return *std::move(type); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 907 | } |
| 908 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 909 | absl::StatusOr<std::vector<Field>> Importer::ImportFields( |
Devin Jeanpierre | d652d93 | 2022-02-03 08:55:33 +0000 | [diff] [blame] | 910 | clang::CXXRecordDecl* record_decl) { |
| 911 | clang::AccessSpecifier default_access = |
| 912 | record_decl->isClass() ? clang::AS_private : clang::AS_public; |
Googler | e3434c3 | 2021-10-19 10:28:35 +0000 | [diff] [blame] | 913 | std::vector<Field> fields; |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 914 | const clang::ASTRecordLayout& layout = ctx_.getASTRecordLayout(record_decl); |
Googler | e3434c3 | 2021-10-19 10:28:35 +0000 | [diff] [blame] | 915 | for (const clang::FieldDecl* field_decl : record_decl->fields()) { |
| 916 | auto type = ConvertType(field_decl->getType()); |
| 917 | if (!type.ok()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 918 | return absl::UnimplementedError( |
| 919 | absl::Substitute("Field type '$0' is not supported", |
| 920 | field_decl->getType().getAsString())); |
Googler | e3434c3 | 2021-10-19 10:28:35 +0000 | [diff] [blame] | 921 | } |
| 922 | clang::AccessSpecifier access = field_decl->getAccess(); |
| 923 | if (access == clang::AS_none) { |
| 924 | access = default_access; |
| 925 | } |
| 926 | |
| 927 | std::optional<Identifier> field_name = GetTranslatedIdentifier(field_decl); |
| 928 | if (!field_name.has_value()) { |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 929 | return absl::UnimplementedError( |
Googler | 279eca3 | 2022-01-04 14:03:44 +0000 | [diff] [blame] | 930 | absl::Substitute("Cannot translate name for field '$0'", |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 931 | field_decl->getNameAsString())); |
Googler | e3434c3 | 2021-10-19 10:28:35 +0000 | [diff] [blame] | 932 | } |
| 933 | fields.push_back( |
| 934 | {.identifier = *std::move(field_name), |
| 935 | .doc_comment = GetComment(field_decl), |
| 936 | .type = *type, |
| 937 | .access = TranslateAccessSpecifier(access), |
Devin Jeanpierre | b69bcae | 2022-02-03 09:45:50 +0000 | [diff] [blame] | 938 | .offset = layout.getFieldOffset(field_decl->getFieldIndex()), |
| 939 | .is_no_unique_address = |
| 940 | field_decl->hasAttr<clang::NoUniqueAddressAttr>()}); |
Googler | e3434c3 | 2021-10-19 10:28:35 +0000 | [diff] [blame] | 941 | } |
| 942 | return fields; |
| 943 | } |
| 944 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 945 | std::string Importer::GetMangledName(const clang::NamedDecl* named_decl) const { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 946 | clang::GlobalDecl decl; |
| 947 | |
| 948 | // There are only three named decl types that don't work with the GlobalDecl |
| 949 | // unary constructor: GPU kernels (which do not exist in standard C++, so we |
| 950 | // ignore), constructors, and destructors. GlobalDecl does not support |
| 951 | // constructors and destructors from the unary constructor because there is |
| 952 | // more than one global declaration for a given constructor or destructor! |
| 953 | // |
| 954 | // * (Ctor|Dtor)_Complete is a function which constructs / destroys the |
| 955 | // entire object. This is what we want. :) |
| 956 | // * Dtor_Deleting is a function which additionally calls operator delete. |
| 957 | // * (Ctor|Dtor)_Base is a function which constructs/destroys the object but |
| 958 | // NOT including virtual base class subobjects. |
| 959 | // * (Ctor|Dtor)_Comdat: I *believe* this is the identifier used to |
| 960 | // deduplicate inline functions, and is not callable. |
| 961 | // * Dtor_(Copying|Default)Closure: These only exist in the MSVC++ ABI, |
| 962 | // which we don't support for now. I don't know when they are used. |
| 963 | // |
| 964 | // It was hard to piece this together, so writing it down here to explain why |
| 965 | // we magically picked the *_Complete variants. |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 966 | if (auto dtor = clang::dyn_cast<clang::CXXDestructorDecl>(named_decl)) { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 967 | decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete); |
| 968 | } else if (auto ctor = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 969 | clang::dyn_cast<clang::CXXConstructorDecl>(named_decl)) { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 970 | decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete); |
| 971 | } else { |
| 972 | decl = clang::GlobalDecl(named_decl); |
| 973 | } |
| 974 | |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 975 | std::string name; |
| 976 | llvm::raw_string_ostream stream(name); |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 977 | mangler_->mangleName(decl, stream); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 978 | stream.flush(); |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 979 | return name; |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 980 | } |
| 981 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 982 | std::optional<UnqualifiedIdentifier> Importer::GetTranslatedName( |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 983 | const clang::NamedDecl* named_decl) const { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 984 | switch (named_decl->getDeclName().getNameKind()) { |
| 985 | case clang::DeclarationName::Identifier: { |
| 986 | auto name = std::string(named_decl->getName()); |
| 987 | if (name.empty()) { |
Lukasz Anforowicz | 0c816f1 | 2021-12-15 17:41:49 +0000 | [diff] [blame] | 988 | if (const clang::ParmVarDecl* param_decl = |
| 989 | clang::dyn_cast<clang::ParmVarDecl>(named_decl)) { |
| 990 | int param_pos = param_decl->getFunctionScopeIndex(); |
| 991 | return {Identifier(absl::StrCat("__param_", param_pos))}; |
| 992 | } |
| 993 | // TODO(lukasza): Handle anonymous structs (probably this won't be an |
| 994 | // issue until nested types are handled - b/200067824). |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 995 | return std::nullopt; |
| 996 | } |
| 997 | return {Identifier(std::move(name))}; |
| 998 | } |
| 999 | case clang::DeclarationName::CXXConstructorName: |
| 1000 | return {SpecialName::kConstructor}; |
| 1001 | case clang::DeclarationName::CXXDestructorName: |
| 1002 | return {SpecialName::kDestructor}; |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1003 | case clang::DeclarationName::CXXOperatorName: |
| 1004 | switch (named_decl->getDeclName().getCXXOverloadedOperator()) { |
| 1005 | case clang::OO_None: |
| 1006 | LOG(FATAL) << "No OO_None expected under CXXOperatorName branch"; |
| 1007 | return std::nullopt; |
| 1008 | case clang::NUM_OVERLOADED_OPERATORS: |
| 1009 | LOG(FATAL) << "No NUM_OVERLOADED_OPERATORS expected at runtime"; |
| 1010 | return std::nullopt; |
| 1011 | // clang-format off |
| 1012 | #define OVERLOADED_OPERATOR(name, spelling, ...) \ |
| 1013 | case clang::OO_##name: { \ |
| 1014 | std::string name = "operator"; \ |
| 1015 | if ('a' <= spelling[0] && spelling[0] <= 'z') { \ |
| 1016 | absl::StrAppend(&name, " "); \ |
| 1017 | } \ |
| 1018 | absl::StrAppend(&name, spelling); \ |
| 1019 | return {Identifier(std::move(name))}; \ |
| 1020 | } |
| 1021 | #include "third_party/llvm/llvm-project/clang/include/clang/Basic/OperatorKinds.def" |
| 1022 | #undef OVERLOADED_OPERATOR |
| 1023 | // clang-format on |
| 1024 | } |
| 1025 | LOG(FATAL) << "The `switch` above should handle all cases and `return`"; |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1026 | default: |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1027 | // To be implemented later: CXXConversionFunctionName. |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1028 | // There are also e.g. literal operators, deduction guides, etc., but |
| 1029 | // we might not need to implement them at all. Full list at: |
| 1030 | // https://clang.llvm.org/doxygen/classclang_1_1DeclarationName.html#a9ab322d434446b43379d39e41af5cbe3 |
| 1031 | return std::nullopt; |
Devin Jeanpierre | e78b2fb | 2021-10-05 11:40:33 +0000 | [diff] [blame] | 1032 | } |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 1033 | } |
| 1034 | |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 1035 | } // namespace rs_bindings_from_cc |