[clang][NFC] Standard substitution checking cleanup

In preparing for module mangling changes I noticed some issues with
the way we check for std::basic_string instantiations and friends.

*) there's a single routine for std::basic_{i,o,io}stream but it is
 templatized on the length of the name.  Really?  just use a
 StringRef, rather than clone the entire routine just for
 'basic_iostream'.

*) We have a helper routine to check for char type, and call it from
 several places.  But given all the instantiations are of the form
 TPL<char, Other<char> ...> we could just check the first arg is char
 and the later templated args are instantiating that same type.  A
 simpler type comparison.

*) Because basic_string has a third allocator parameter, it is open
 coded, which I found a little confusing.  But otherwise it's exactly
 the same pattern as the iostream ones.  Just tell that checker about
 whether there's an expected allocator argument.[*]

*) We may as well return in each block of mangleStandardSubstitution
 once we determine it is not one of the entities of interest -- it
 certainly cannot be one of the other kinds of entities.

FWIW this shaves about 500 bytes off the executable.

[*] I suppose we could also have this routine a tri-value, with one to
indicat 'it is this name, but it's not the one you're looking for', to
avoid later calls trying different names?

Reviewd By: ChuanqiXu

Differential Revision: https://reviews.llvm.org/D119333
This commit is contained in:
Nathan Sidwell 2022-02-09 06:09:35 -08:00
parent c77de9490e
commit 815446cd3e

View file

@ -5969,27 +5969,19 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
return true;
}
static bool isCharType(QualType T) {
if (T.isNull())
/// Returns whether S is a template specialization of std::Name with a single
/// argument of type A.
static bool isSpecializedAs(QualType S, llvm::StringRef Name, QualType A) {
if (S.isNull())
return false;
return T->isSpecificBuiltinType(BuiltinType::Char_S) ||
T->isSpecificBuiltinType(BuiltinType::Char_U);
}
/// Returns whether a given type is a template specialization of a given name
/// with a single argument of type char.
static bool isCharSpecialization(QualType T, const char *Name) {
if (T.isNull())
return false;
const RecordType *RT = T->getAs<RecordType>();
const RecordType *RT = S->getAs<RecordType>();
if (!RT)
return false;
const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
if (!SD)
if (!SD || !SD->getIdentifier()->isStr(Name))
return false;
if (!isStdNamespace(getEffectiveDeclContext(SD)))
@ -5999,26 +5991,37 @@ static bool isCharSpecialization(QualType T, const char *Name) {
if (TemplateArgs.size() != 1)
return false;
if (!isCharType(TemplateArgs[0].getAsType()))
if (TemplateArgs[0].getAsType() != A)
return false;
return SD->getIdentifier()->getName() == Name;
return true;
}
template <std::size_t StrLen>
static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD,
const char (&Str)[StrLen]) {
if (!SD->getIdentifier()->isStr(Str))
/// Returns whether SD is a template specialization std::Name<char,
/// std::char_traits<char> [, std::allocator<char>]>
/// HasAllocator controls whether the 3rd template argument is needed.
static bool isStdCharSpecialization(const ClassTemplateSpecializationDecl *SD,
llvm::StringRef Name, bool HasAllocator) {
if (!SD->getIdentifier()->isStr(Name))
return false;
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
if (TemplateArgs.size() != 2)
if (TemplateArgs.size() != (HasAllocator ? 3 : 2))
return false;
if (!isCharType(TemplateArgs[0].getAsType()))
QualType A = TemplateArgs[0].getAsType();
if (A.isNull())
return false;
// Plain 'char' is named Char_S or Char_U depending on the target ABI.
if (!A->isSpecificBuiltinType(BuiltinType::Char_S) &&
!A->isSpecificBuiltinType(BuiltinType::Char_U))
return false;
if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
if (!isSpecializedAs(TemplateArgs[1].getAsType(), "char_traits", A))
return false;
if (HasAllocator &&
!isSpecializedAs(TemplateArgs[2].getAsType(), "allocator", A))
return false;
return true;
@ -6031,6 +6034,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
Out << "St";
return true;
}
return false;
}
if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
@ -6048,6 +6052,7 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
Out << "Sb";
return true;
}
return false;
}
if (const ClassTemplateSpecializationDecl *SD =
@ -6058,46 +6063,34 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
// <substitution> ::= Ss # ::std::basic_string<char,
// ::std::char_traits<char>,
// ::std::allocator<char> >
if (SD->getIdentifier()->isStr("basic_string")) {
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
if (TemplateArgs.size() != 3)
return false;
if (!isCharType(TemplateArgs[0].getAsType()))
return false;
if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
return false;
if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator"))
return false;
if (isStdCharSpecialization(SD, "basic_string", /*HasAllocator=*/true)) {
Out << "Ss";
return true;
}
// <substitution> ::= Si # ::std::basic_istream<char,
// ::std::char_traits<char> >
if (isStreamCharSpecialization(SD, "basic_istream")) {
if (isStdCharSpecialization(SD, "basic_istream", /*HasAllocator=*/false)) {
Out << "Si";
return true;
}
// <substitution> ::= So # ::std::basic_ostream<char,
// ::std::char_traits<char> >
if (isStreamCharSpecialization(SD, "basic_ostream")) {
if (isStdCharSpecialization(SD, "basic_ostream", /*HasAllocator=*/false)) {
Out << "So";
return true;
}
// <substitution> ::= Sd # ::std::basic_iostream<char,
// ::std::char_traits<char> >
if (isStreamCharSpecialization(SD, "basic_iostream")) {
if (isStdCharSpecialization(SD, "basic_iostream", /*HasAllocator=*/false)) {
Out << "Sd";
return true;
}
return false;
}
return false;
}