Skip to content

Commit 2d5da0c

Browse files
committed
Implement compression mangling
1 parent 96b59b4 commit 2d5da0c

File tree

1 file changed

+228
-1
lines changed

1 file changed

+228
-1
lines changed

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 228 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,19 @@ class CXXNameMangler {
461461

462462
void mangleExistingSubstitution(TemplateName name);
463463

464+
struct Namespaces {
465+
const NamespaceDecl *NS;
466+
std::string_view InnerNamespace{};
467+
};
468+
469+
auto specializedClassInNamespace(
470+
std::string_view Name, Namespaces NS,
471+
std::initializer_list<
472+
llvm::function_ref<bool(const TemplateArgument &)>>);
473+
template <class... Args> auto anyBuiltin(Args... Builtins);
474+
464475
bool mangleStandardSubstitution(const NamedDecl *ND);
476+
bool mangleVersionedStandardSubstitution(const NamedDecl *ND);
465477

466478
void addSubstitution(const NamedDecl *ND) {
467479
ND = cast<NamedDecl>(ND->getCanonicalDecl());
@@ -6319,16 +6331,227 @@ bool CXXNameMangler::isStdCharSpecialization(
63196331
return true;
63206332
}
63216333

6334+
static bool isSpecialization(const ClassTemplateSpecializationDecl *SD,
6335+
std::string_view Name,
6336+
std::initializer_list<llvm::function_ref<bool(const TemplateArgument&)>> Args) {
6337+
if (!SD->getIdentifier()->isStr(Name))
6338+
return false;
6339+
6340+
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())
6341+
return false;
6342+
6343+
const auto& TemplateArgs = SD->getTemplateArgs();
6344+
if (TemplateArgs.size() != Args.size())
6345+
return false;
6346+
6347+
return llvm::all_of(llvm::zip(Args, TemplateArgs.asArray()), [](auto Arg) {
6348+
return std::get<0>(Arg)(std::get<1>(Arg));
6349+
});
6350+
}
6351+
6352+
auto CXXNameMangler::specializedClassInNamespace(
6353+
std::string_view Name, Namespaces NS,
6354+
std::initializer_list<llvm::function_ref<bool(const TemplateArgument &)>>
6355+
Args) {
6356+
return [=, this](const TemplateArgument &Type) -> bool {
6357+
const auto* RT = Type.getAsType()->getAs<RecordType>();
6358+
if (!RT)
6359+
return false;
6360+
const auto* SD = dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
6361+
if (!SD || !SD->getIdentifier()->isStr(Name))
6362+
return false;
6363+
6364+
const auto *DC = Context.getEffectiveDeclContext(SD);
6365+
if (!DC->isNamespace())
6366+
return false;
6367+
const auto *ND = cast<NamespaceDecl>(DC);
6368+
if (NS.InnerNamespace != "") {
6369+
if (ND->getIdentifier()->getName() != StringRef(NS.InnerNamespace))
6370+
return false;
6371+
if (!ND->getParent()->isNamespace())
6372+
return false;
6373+
ND = cast<NamespaceDecl>(ND->getParent());
6374+
}
6375+
if (ND->getOriginalNamespace() != NS.NS->getOriginalNamespace())
6376+
return false;
6377+
return isSpecialization(SD, Name, Args);
6378+
};
6379+
}
6380+
6381+
template <class... Args>
6382+
auto CXXNameMangler::anyBuiltin(Args... Builtins) {
6383+
return [=](const TemplateArgument &TA) {
6384+
auto QT = TA.getAsType();
6385+
return (QT->isSpecificBuiltinType(Builtins) || ...);
6386+
};
6387+
}
6388+
6389+
static bool isVersionedStdNamespace(const DeclContext *DC) {
6390+
if (!DC->getEnclosingNamespaceContext()->isStdNamespace())
6391+
return false;
6392+
if (!DC->isNamespace())
6393+
return false;
6394+
auto Name = cast<NamespaceDecl>(DC)->getIdentifier()->getName();
6395+
if (!Name.starts_with("__"))
6396+
return false;
6397+
Name = Name.drop_front(2);
6398+
auto NoVersion = Name.drop_while([](char c) { return std::isdigit(c); });
6399+
if (NoVersion.size() == Name.size())
6400+
return false;
6401+
return NoVersion.size() == 1 && std::islower(NoVersion[0]);
6402+
}
6403+
6404+
bool CXXNameMangler::mangleVersionedStandardSubstitution(const NamedDecl *ND) {
6405+
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
6406+
if (isVersionedStdNamespace(NS)) {
6407+
auto Name = NS->getName().drop_front(2);
6408+
Out << "S" << Name << "T";
6409+
return true;
6410+
}
6411+
}
6412+
6413+
if (!isVersionedStdNamespace(ND->getDeclContext()))
6414+
return false;
6415+
6416+
auto Version = cast<NamespaceDecl>(ND->getDeclContext())
6417+
->getIdentifier()
6418+
->getName()
6419+
.drop_front(2);
6420+
6421+
if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
6422+
const auto *EnclosingNamespace = Context.getEffectiveDeclContext(TD);
6423+
if (isVersionedStdNamespace(EnclosingNamespace)) {
6424+
if (TD->getOwningModuleForLinkage())
6425+
return false;
6426+
6427+
static std::pair<std::string_view, std::string_view> replacements[] {
6428+
{"allocator", "aL"},
6429+
{"atomic", "aT"},
6430+
{"expected", "eX"},
6431+
{"vector", "vE"},
6432+
{"copyable_function", "fC"},
6433+
{"function", "fF"},
6434+
{"move_only_function", "fM"},
6435+
{"function_ref", "fF"},
6436+
{"optional", "oP"},
6437+
{"shared_ptr", "sP"},
6438+
{"tuple", "tU"},
6439+
{"variant", "vA"},
6440+
};
6441+
6442+
for (auto [name, substitution] : replacements) {
6443+
if (TD->getIdentifier()->isStr(name)) {
6444+
Out << "S" << Version << substitution;
6445+
return true;
6446+
}
6447+
}
6448+
}
6449+
}
6450+
6451+
if (const ClassTemplateSpecializationDecl *SD =
6452+
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
6453+
const auto *EnclosingNamespace = SD->getEnclosingNamespaceContext();
6454+
if (isVersionedStdNamespace(EnclosingNamespace)) {
6455+
const auto *NS = cast<NamespaceDecl>(EnclosingNamespace);
6456+
6457+
{ // char strings
6458+
auto Char = anyBuiltin(BuiltinType::Char_S, BuiltinType::Char_U);
6459+
auto CharTraitsChar =
6460+
specializedClassInNamespace("char_traits", {NS}, {Char});
6461+
auto AllocatorChar =
6462+
specializedClassInNamespace("allocator", {NS}, {Char});
6463+
auto PolymorphicAllocatorChar = specializedClassInNamespace(
6464+
"polymorphic_allocator", {NS, "pmr"}, {Char});
6465+
6466+
if (isSpecialization(SD, "basic_string",
6467+
{Char, CharTraitsChar, AllocatorChar})) {
6468+
Out << "S" << Version << "S";
6469+
return true;
6470+
}
6471+
if (isSpecialization(SD, "basic_string",
6472+
{Char, CharTraitsChar, PolymorphicAllocatorChar})) {
6473+
Out << "S" << Version << "sA";
6474+
return true;
6475+
}
6476+
if (isSpecialization(SD, "basic_string_view", {Char, CharTraitsChar})) {
6477+
Out << "S" << Version << "sB";
6478+
return true;
6479+
}
6480+
if (isSpecialization(SD, "basic_istream", {Char, CharTraitsChar})) {
6481+
Out << "S" << Version << "bI";
6482+
return true;
6483+
}
6484+
if (isSpecialization(SD, "basic_ostream", {Char, CharTraitsChar})) {
6485+
Out << "S" << Version << "bO";
6486+
return true;
6487+
}
6488+
if (isSpecialization(SD, "basic_iostream", {Char, CharTraitsChar})) {
6489+
Out << "S" << Version << "bS";
6490+
return true;
6491+
}
6492+
}
6493+
6494+
{ // wchar strings
6495+
auto WChar = anyBuiltin(BuiltinType::WChar_S, BuiltinType::WChar_U);
6496+
auto CharTraitsWChar =
6497+
specializedClassInNamespace("char_traits", {NS}, {WChar});
6498+
auto AllocatorWChar =
6499+
specializedClassInNamespace("allocator", {NS}, {WChar});
6500+
auto PolymorphicAllocatorWChar = specializedClassInNamespace(
6501+
"polymorphic_allocator", {NS, "pmr"}, {WChar});
6502+
6503+
if (isSpecialization(SD, "basic_string",
6504+
{WChar, CharTraitsWChar, AllocatorWChar})) {
6505+
Out << "S" << Version << "sC";
6506+
return true;
6507+
}
6508+
if (isSpecialization(
6509+
SD, "basic_string",
6510+
{WChar, CharTraitsWChar, PolymorphicAllocatorWChar})) {
6511+
Out << "S" << Version << "sD";
6512+
return true;
6513+
}
6514+
if (isSpecialization(SD, "basic_string_view", {WChar, CharTraitsWChar})) {
6515+
Out << "S" << Version << "sE";
6516+
return true;
6517+
}
6518+
}
6519+
6520+
{ // complex
6521+
if (isSpecialization(SD, "complex", {anyBuiltin(BuiltinType::Float)})) {
6522+
Out << "S" << Version << "cF";
6523+
return true;
6524+
}
6525+
if (isSpecialization(SD, "complex", {anyBuiltin(BuiltinType::Double)})) {
6526+
Out << "S" << Version << "cD";
6527+
return true;
6528+
}
6529+
if (isSpecialization(SD, "complex", {anyBuiltin(BuiltinType::LongDouble)})) {
6530+
Out << "S" << Version << "cL";
6531+
return true;
6532+
}
6533+
}
6534+
}
6535+
}
6536+
6537+
return false;
6538+
}
6539+
63226540
bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
63236541
// <substitution> ::= St # ::std::
63246542
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
63256543
if (isStd(NS)) {
63266544
Out << "St";
63276545
return true;
63286546
}
6547+
if (isVersionedStdNamespace(NS))
6548+
return mangleVersionedStandardSubstitution(ND);
63296549
return false;
63306550
}
63316551

6552+
if (ND->isInStdNamespace())
6553+
return mangleVersionedStandardSubstitution(ND);
6554+
63326555
if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
63336556
if (!isStdNamespace(Context.getEffectiveDeclContext(TD)))
63346557
return false;
@@ -6352,7 +6575,11 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
63526575

63536576
if (const ClassTemplateSpecializationDecl *SD =
63546577
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
6355-
if (!isStdNamespace(Context.getEffectiveDeclContext(SD)))
6578+
const DeclContext *DC = Context.getEffectiveDeclContext(ND);
6579+
if (isVersionedStdNamespace(DC))
6580+
return mangleVersionedStandardSubstitution(ND);
6581+
6582+
if (!isStdNamespace(DC))
63566583
return false;
63576584

63586585
if (SD->getSpecializedTemplate()->getOwningModuleForLinkage())

0 commit comments

Comments
 (0)