| // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| // Exceptions. See /LICENSE for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| #include "rs_bindings_from_cc/ast_convert.h" |
| |
| #include "absl/functional/function_ref.h" |
| #include "absl/log/check.h" |
| #include "rs_bindings_from_cc/ir.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclCXX.h" |
| #include "clang/Basic/LLVM.h" |
| #include "clang/Basic/Specifiers.h" |
| |
| namespace crubit { |
| namespace { |
| |
| // Returns a copy constructor for `record`, or `nullptr` if none is declared. |
| // |
| // Does not traverse to the base classes. |
| static const clang::CXXConstructorDecl* GetCopyCtor( |
| const clang::CXXRecordDecl* record) { |
| for (clang::CXXConstructorDecl* ctor_decl : record->ctors()) { |
| if (ctor_decl->isCopyConstructor()) { |
| return ctor_decl; |
| } |
| } |
| return nullptr; |
| } |
| |
| // Returns a move constructor for `record`, or `nullptr` if none is declared. |
| // |
| // Does not traverse to the base classes. |
| static const clang::CXXConstructorDecl* GetMoveCtor( |
| const clang::CXXRecordDecl* record) { |
| for (clang::CXXConstructorDecl* ctor_decl : record->ctors()) { |
| if (ctor_decl->isMoveConstructor()) { |
| return ctor_decl; |
| } |
| } |
| return nullptr; |
| } |
| |
| // Returns true if this class, and all base classes, only define the specified |
| // special member implicitly or via =default, and only do so non-virtually. |
| // |
| // Args: |
| // record: the class/struct to check. |
| // getter: a function which returns the special member function in question. |
| // returns null if the special member function is implicitly defined. |
| bool HasNoUserProvidedSpecialMember( |
| const clang::CXXRecordDecl* record, |
| absl::FunctionRef<const clang::CXXMethodDecl*(const clang::CXXRecordDecl*)> |
| getter) { |
| auto nonrecursive_has_only_defaulted = |
| [&getter](const clang::CXXRecordDecl* record) { |
| const clang::CXXMethodDecl* decl = getter(record); |
| return decl == nullptr || |
| (!decl->isUserProvided() && !decl->isVirtual()); |
| }; |
| |
| if (!nonrecursive_has_only_defaulted(record)) { |
| return false; |
| } |
| return record->forallBases(nonrecursive_has_only_defaulted); |
| } |
| |
| SpecialMemberFunc GetSpecialMemberFunc( |
| const clang::RecordDecl& record_decl, |
| absl::FunctionRef<const clang::CXXMethodDecl*(const clang::CXXRecordDecl*)> |
| getter) { |
| const auto* cxx_record_decl = |
| clang::dyn_cast<clang::CXXRecordDecl>(&record_decl); |
| if (cxx_record_decl == nullptr) { |
| return SpecialMemberFunc::kTrivial; |
| } |
| |
| const clang::CXXMethodDecl* decl = getter(cxx_record_decl); |
| if (decl == nullptr) { |
| return SpecialMemberFunc::kUnavailable; |
| } |
| |
| switch (decl->getAccess()) { |
| case clang::AS_public: |
| break; |
| case clang::AS_protected: |
| case clang::AS_private: |
| return SpecialMemberFunc::kUnavailable; |
| case clang::AS_none: |
| CHECK(false && |
| "We should never be encoding a 'none' access specifier in IR."); |
| // We have to return something. kDeleted seems like a safe fallback. |
| return SpecialMemberFunc::kUnavailable; |
| } |
| |
| if (decl->isDeleted()) { |
| return SpecialMemberFunc::kUnavailable; |
| } else if (decl->isTrivial()) { |
| return SpecialMemberFunc::kTrivial; |
| } else if (HasNoUserProvidedSpecialMember(cxx_record_decl, getter)) { |
| return SpecialMemberFunc::kNontrivialMembers; |
| } else { |
| return SpecialMemberFunc::kNontrivialUserDefined; |
| } |
| } |
| |
| } // namespace |
| |
| SpecialMemberFunc GetCopyCtorSpecialMemberFunc( |
| const clang::RecordDecl& record_decl) { |
| return GetSpecialMemberFunc(record_decl, &GetCopyCtor); |
| } |
| |
| SpecialMemberFunc GetMoveCtorSpecialMemberFunc( |
| const clang::RecordDecl& record_decl) { |
| return GetSpecialMemberFunc(record_decl, &GetMoveCtor); |
| } |
| |
| SpecialMemberFunc GetDestructorSpecialMemberFunc( |
| const clang::RecordDecl& record_decl) { |
| return GetSpecialMemberFunc(record_decl, |
| [](auto c) { return c->getDestructor(); }); |
| } |
| |
| } // namespace crubit |