Initial support for non-identifier names (currently: constructors, destructors), but without much special support in codegen.
PiperOrigin-RevId: 402912788
diff --git a/rs_bindings_from_cc/ast_visitor.cc b/rs_bindings_from_cc/ast_visitor.cc
index b148673..f88f28c 100644
--- a/rs_bindings_from_cc/ast_visitor.cc
+++ b/rs_bindings_from_cc/ast_visitor.cc
@@ -72,7 +72,7 @@
success = false;
continue;
}
- std::optional<Identifier> param_name = GetTranslatedName(param);
+ std::optional<Identifier> param_name = GetTranslatedIdentifier(param);
if (!param_name.has_value()) {
ir_.items.push_back(UnsupportedItem{
.name = function_decl->getQualifiedNameAsString(),
@@ -95,11 +95,11 @@
function_decl->getReturnTypeSourceRange().getBegin())});
success = false;
}
- std::optional<Identifier> translated_name = GetTranslatedName(function_decl);
- // For example, the destructor doesn't have a name.
+ std::optional<UnqualifiedIdentifier> translated_name =
+ GetTranslatedName(function_decl);
if (success && translated_name.has_value()) {
ir_.items.push_back(Func{
- .identifier = *translated_name,
+ .name = *translated_name,
.doc_comment = GetComment(function_decl),
.mangled_name = GetMangledName(function_decl),
.return_type = *return_type,
@@ -210,7 +210,7 @@
access = default_access;
}
- std::optional<Identifier> field_name = GetTranslatedName(field_decl);
+ std::optional<Identifier> field_name = GetTranslatedIdentifier(field_decl);
if (!field_name.has_value()) {
return true;
}
@@ -221,7 +221,7 @@
.access = TranslateAccessSpecifier(access),
.offset = layout.getFieldOffset(field_decl->getFieldIndex())});
}
- std::optional<Identifier> record_name = GetTranslatedName(record_decl);
+ std::optional<Identifier> record_name = GetTranslatedIdentifier(record_decl);
if (!record_name.has_value()) {
return true;
}
@@ -329,20 +329,64 @@
std::string AstVisitor::GetMangledName(
const clang::NamedDecl* named_decl) const {
+ clang::GlobalDecl decl;
+
+ // There are only three named decl types that don't work with the GlobalDecl
+ // unary constructor: GPU kernels (which do not exist in standard C++, so we
+ // ignore), constructors, and destructors. GlobalDecl does not support
+ // constructors and destructors from the unary constructor because there is
+ // more than one global declaration for a given constructor or destructor!
+ //
+ // * (Ctor|Dtor)_Complete is a function which constructs / destroys the
+ // entire object. This is what we want. :)
+ // * Dtor_Deleting is a function which additionally calls operator delete.
+ // * (Ctor|Dtor)_Base is a function which constructs/destroys the object but
+ // NOT including virtual base class subobjects.
+ // * (Ctor|Dtor)_Comdat: I *believe* this is the identifier used to
+ // deduplicate inline functions, and is not callable.
+ // * Dtor_(Copying|Default)Closure: These only exist in the MSVC++ ABI,
+ // which we don't support for now. I don't know when they are used.
+ //
+ // It was hard to piece this together, so writing it down here to explain why
+ // we magically picked the *_Complete variants.
+ if (auto dtor = llvm::dyn_cast<clang::CXXDestructorDecl>(named_decl)) {
+ decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete);
+ } else if (auto ctor =
+ llvm::dyn_cast<clang::CXXConstructorDecl>(named_decl)) {
+ decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete);
+ } else {
+ decl = clang::GlobalDecl(named_decl);
+ }
+
std::string name;
llvm::raw_string_ostream stream(name);
- mangler_->mangleName(named_decl, stream);
+ mangler_->mangleName(decl, stream);
stream.flush();
return name;
}
-std::optional<Identifier> AstVisitor::GetTranslatedName(
+std::optional<UnqualifiedIdentifier> AstVisitor::GetTranslatedName(
const clang::NamedDecl* named_decl) const {
- clang::IdentifierInfo* id = named_decl->getIdentifier();
- if (id == nullptr) {
- return std::nullopt;
+ switch (named_decl->getDeclName().getNameKind()) {
+ case clang::DeclarationName::Identifier: {
+ auto name = std::string(named_decl->getName());
+ if (name.empty()) {
+ // for example, a parameter with no name.
+ return std::nullopt;
+ }
+ return {Identifier(std::move(name))};
+ }
+ case clang::DeclarationName::CXXConstructorName:
+ return {SpecialName::kConstructor};
+ case clang::DeclarationName::CXXDestructorName:
+ return {SpecialName::kDestructor};
+ default:
+ // To be implemented later: operators, conversion functions.
+ // There are also e.g. literal operators, deduction guides, etc., but
+ // we might not need to implement them at all. Full list at:
+ // https://clang.llvm.org/doxygen/classclang_1_1DeclarationName.html#a9ab322d434446b43379d39e41af5cbe3
+ return std::nullopt;
}
- return Identifier(std::string(id->getName()));
}
void AstVisitor::CommentManager::TraverseDecl(clang::Decl* decl) {