blob: 8f635f18b071a978e1c980414144b88ecfa912d3 [file] [log] [blame]
// 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"
namespace rs_bindings_from_cc {
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.
//
// 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.
// Signature: `const clang::FunctionDecl* (const clang::CXXRecordDecl*)`.
template <typename F>
bool HasNoUserProvidedSpecialMember(const clang::CXXRecordDecl* record,
const F& getter) {
auto nonrecursive_has_only_defaulted =
[&getter](const clang::CXXRecordDecl* record) {
const clang::FunctionDecl* decl = getter(record);
return decl == nullptr || !decl->isUserProvided();
};
if (!nonrecursive_has_only_defaulted(record)) {
return false;
}
return record->forallBases(nonrecursive_has_only_defaulted);
}
} // namespace
AccessSpecifier TranslateAccessSpecifier(clang::AccessSpecifier access) {
switch (access) {
case clang::AS_public:
return kPublic;
case clang::AS_protected:
return kProtected;
case clang::AS_private:
return kPrivate;
case clang::AS_none:
// We should never be encoding a "none" access specifier in IR.
assert(false);
// We have to return something. Conservatively return private so we don't
// inadvertently make a private member variable accessible in Rust.
return kPrivate;
}
}
SpecialMemberFunc GetCopyCtorSpecialMemberFunc(
const clang::RecordDecl& record_decl) {
SpecialMemberFunc copy_ctor = {
.definition = SpecialMemberFunc::Definition::kTrivial,
.access = kPublic,
};
const auto* cxx_record_decl =
clang::dyn_cast<clang::CXXRecordDecl>(&record_decl);
if (cxx_record_decl == nullptr) {
return copy_ctor;
}
const clang::CXXConstructorDecl* copy_ctor_decl =
GetCopyCtor(cxx_record_decl);
if (copy_ctor_decl == nullptr) {
copy_ctor.definition = SpecialMemberFunc::Definition::kDeleted;
return copy_ctor;
}
copy_ctor.access = TranslateAccessSpecifier(copy_ctor_decl->getAccess());
if (copy_ctor_decl->isDeleted()) {
copy_ctor.definition = SpecialMemberFunc::Definition::kDeleted;
} else if (copy_ctor_decl->isTrivial()) {
copy_ctor.definition = SpecialMemberFunc::Definition::kTrivial;
} else if (HasNoUserProvidedSpecialMember(cxx_record_decl, &GetCopyCtor)) {
copy_ctor.definition = SpecialMemberFunc::Definition::kNontrivialMembers;
} else {
copy_ctor.definition = SpecialMemberFunc::Definition::kNontrivialSelf;
}
return copy_ctor;
}
SpecialMemberFunc GetMoveCtorSpecialMemberFunc(
const clang::RecordDecl& record_decl) {
SpecialMemberFunc move_ctor = {
.definition = SpecialMemberFunc::Definition::kTrivial,
.access = kPublic,
};
const auto* cxx_record_decl =
clang::dyn_cast<clang::CXXRecordDecl>(&record_decl);
if (cxx_record_decl == nullptr) {
return move_ctor;
}
const clang::CXXConstructorDecl* move_ctor_decl =
GetMoveCtor(cxx_record_decl);
if (move_ctor_decl == nullptr) {
move_ctor.definition = SpecialMemberFunc::Definition::kDeleted;
return move_ctor;
}
move_ctor.access = TranslateAccessSpecifier(move_ctor_decl->getAccess());
if (move_ctor_decl->isDeleted()) {
move_ctor.definition = SpecialMemberFunc::Definition::kDeleted;
} else if (move_ctor_decl->isTrivial()) {
move_ctor.definition = SpecialMemberFunc::Definition::kTrivial;
} else if (HasNoUserProvidedSpecialMember(cxx_record_decl, &GetMoveCtor)) {
move_ctor.definition = SpecialMemberFunc::Definition::kNontrivialMembers;
} else {
move_ctor.definition = SpecialMemberFunc::Definition::kNontrivialSelf;
}
return move_ctor;
}
SpecialMemberFunc GetDestructorSpecialMemberFunc(
const clang::RecordDecl& record_decl) {
SpecialMemberFunc dtor = {
.definition = SpecialMemberFunc::Definition::kTrivial,
.access = kPublic,
};
const auto* cxx_record_decl =
clang::dyn_cast<clang::CXXRecordDecl>(&record_decl);
if (cxx_record_decl == nullptr) {
return dtor;
}
const clang::CXXDestructorDecl* dtor_decl = cxx_record_decl->getDestructor();
if (dtor_decl == nullptr) {
dtor.definition = SpecialMemberFunc::Definition::kDeleted;
return dtor;
}
dtor.access = TranslateAccessSpecifier(dtor_decl->getAccess());
if (dtor_decl->isDeleted()) {
dtor.definition = SpecialMemberFunc::Definition::kDeleted;
} else if (dtor_decl->isTrivial()) {
dtor.definition = SpecialMemberFunc::Definition::kTrivial;
} else if (HasNoUserProvidedSpecialMember(
cxx_record_decl, [](auto c) { return c->getDestructor(); })) {
dtor.definition = SpecialMemberFunc::Definition::kNontrivialMembers;
} else {
dtor.definition = SpecialMemberFunc::Definition::kNontrivialSelf;
}
return dtor;
}
} // namespace rs_bindings_from_cc