[clang] 4b163e3 - Implement mangling rules for C++20 concepts and requires-expressions.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 20 12:38:38 PDT 2023
Author: Richard Smith
Date: 2023-09-20T12:38:15-07:00
New Revision: 4b163e343cfa54c8d55c9da73c70d58f55ea9df2
URL: https://github.com/llvm/llvm-project/commit/4b163e343cfa54c8d55c9da73c70d58f55ea9df2
DIFF: https://github.com/llvm/llvm-project/commit/4b163e343cfa54c8d55c9da73c70d58f55ea9df2.diff
LOG: Implement mangling rules for C++20 concepts and requires-expressions.
This implements proposals from:
- https://github.com/itanium-cxx-abi/cxx-abi/issues/24: mangling for
constraints, requires-clauses, requires-expressions.
- https://github.com/itanium-cxx-abi/cxx-abi/issues/31: requires-clauses and
template parameters in a lambda expression are mangled into the <lambda-sig>.
- https://github.com/itanium-cxx-abi/cxx-abi/issues/47 (STEP 3): mangling for
template argument is prefixed by mangling of template parameter declaration
if it's not "obvious", for example because the template parameter is
constrained (we already implemented STEP 1 and STEP 2).
This changes the manglings for a few cases:
- Functions and function templates with constraints.
- Function templates with template parameters with deduced types:
`typename<auto N> void f();`
- Function templates with template template parameters where the argument has a
different template-head:
`template<template<typename...T>> void f(); f<std::vector>();`
In each case where a mangling changed, the change fixes a mangling collision.
Note that only function templates are affected, not class templates or variable
templates, and only new constructs (template parameters with deduced types,
constrained templates) and esoteric constructs (templates with template
template parameters with non-matching template template arguments, most of
which Clang still does not accept by default due to
`-frelaxed-template-template-args` not being enabled by default), so the risk
to ABI stability from this change is relatively low. Nonetheless,
`-fclang-abi-compat=17` can be used to restore the old manglings for cases
which we could successfully but incorrectly mangle before.
Fixes #48216, #49884, #61273
Reviewed By: erichkeane, #libc_abi
Differential Revision: https://reviews.llvm.org/D147655
Added:
clang/test/CodeGenCXX/mangle-requires.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/ExprConcepts.h
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ExprConcepts.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/Parse/ParseExprCXX.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/CodeGenCXX/mangle-concept.cpp
clang/test/CodeGenCXX/mangle-exprs.cpp
clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp
clang/test/CodeGenCXX/mangle-template.cpp
clang/test/CodeGenCXX/matrix-type.cpp
clang/test/OpenMP/tile_codegen.cpp
libcxxabi/src/demangle/ItaniumDemangle.h
libcxxabi/src/demangle/ItaniumNodes.def
libcxxabi/test/test_demangle.pass.cpp
llvm/include/llvm/Demangle/ItaniumDemangle.h
llvm/include/llvm/Demangle/ItaniumNodes.def
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 43b113d00a50956..3cf2d4f6cfb30cc 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -46,6 +46,24 @@ C/C++ Language Potentially Breaking Changes
C++ Specific Potentially Breaking Changes
-----------------------------------------
+- The name mangling rules for function templates has been changed to take into
+ account the possibility that functions could be overloaded on their template
+ parameter lists or requires-clauses. This causes mangled names to change for
+ function templates in the following cases:
+ - When the function has any constraints, whether from constrained template
+ parameters or requires-clauses.
+ - When the template parameter list includes a deduced type -- either
+ ``auto``, ``decltype(auto)``, or a deduced class template specialization
+ type.
+ - When a template template parameter is given a template template argument
+ that has a
diff erent template parameter list.
+ This fixes a number of issues where valid programs would be rejected due to
+ mangling collisions, or would in some cases be silently miscompiled. Clang
+ will use the old manglings if ``-fclang-abi-compat=17`` or lower is
+ specified.
+ (`#48216 <https://github.com/llvm/llvm-project/issues/48216>`_),
+ (`#49884 <https://github.com/llvm/llvm-project/issues/49884>`_), and
+ (`#61273 <https://github.com/llvm/llvm-project/issues/61273>`_)
ABI Changes in This Version
---------------------------
diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h
index 6f38b2c4b057148..4f34799bad05021 100644
--- a/clang/include/clang/AST/ExprConcepts.h
+++ b/clang/include/clang/AST/ExprConcepts.h
@@ -511,6 +511,8 @@ class RequiresExpr final : public Expr,
unsigned NumLocalParameters;
unsigned NumRequirements;
RequiresExprBodyDecl *Body;
+ SourceLocation LParenLoc;
+ SourceLocation RParenLoc;
SourceLocation RBraceLoc;
unsigned numTrailingObjects(OverloadToken<ParmVarDecl *>) const {
@@ -522,19 +524,22 @@ class RequiresExpr final : public Expr,
}
RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
- RequiresExprBodyDecl *Body,
+ RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
+ SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc);
RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
unsigned NumRequirements);
public:
- static RequiresExpr *
- Create(ASTContext &C, SourceLocation RequiresKWLoc,
- RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> LocalParameters,
- ArrayRef<concepts::Requirement *> Requirements,
- SourceLocation RBraceLoc);
+ static RequiresExpr *Create(ASTContext &C, SourceLocation RequiresKWLoc,
+ RequiresExprBodyDecl *Body,
+ SourceLocation LParenLoc,
+ ArrayRef<ParmVarDecl *> LocalParameters,
+ SourceLocation RParenLoc,
+ ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc);
static RequiresExpr *
Create(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters,
unsigned NumRequirements);
@@ -567,6 +572,8 @@ class RequiresExpr final : public Expr,
return RequiresExprBits.RequiresKWLoc;
}
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+ SourceLocation getRParenLoc() const { return RParenLoc; }
SourceLocation getRBraceLoc() const { return RBraceLoc; }
static bool classof(const Stmt *T) {
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index fb073bf16bbf2bd..e0e95f6d26f4545 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -231,6 +231,15 @@ class LangOptions : public LangOptionsBase {
/// - consider classes with defaulted special member functions non-pod.
Ver15,
+ /// Attempt to be ABI-compatible with code generated by Clang 17.0.x.
+ /// This causes clang to revert some fixes to its implementation of the
+ /// Itanium name mangling scheme, with the consequence that overloaded
+ /// function templates are mangled the same if they
diff er only by:
+ /// - constraints
+ /// - whether a non-type template parameter has a deduced type
+ /// - the parameter list of a template template parameter
+ Ver17,
+
/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 47379e00a7445e3..712db0a3dd895d5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8724,7 +8724,9 @@ class Sema final {
const ASTConstraintSatisfaction &Satisfaction);
ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body,
+ SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
+ SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation ClosingBraceLoc);
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index 2aa15049a7ff23b..0704630c0fc2664 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -117,13 +117,15 @@ static bool RequirementContainsError(concepts::Requirement *R) {
}
RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
- RequiresExprBodyDecl *Body,
+ RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
+ SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation RBraceLoc)
: Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
NumLocalParameters(LocalParameters.size()),
- NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
+ NumRequirements(Requirements.size()), Body(Body), LParenLoc(LParenLoc),
+ RParenLoc(RParenLoc), RBraceLoc(RBraceLoc) {
RequiresExprBits.IsSatisfied = false;
RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
bool Dependent = false;
@@ -168,18 +170,18 @@ RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
: Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
NumRequirements(NumRequirements) { }
-RequiresExpr *
-RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
- RequiresExprBodyDecl *Body,
- ArrayRef<ParmVarDecl *> LocalParameters,
- ArrayRef<concepts::Requirement *> Requirements,
- SourceLocation RBraceLoc) {
+RequiresExpr *RequiresExpr::Create(
+ ASTContext &C, SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body,
+ SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters,
+ SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation RBraceLoc) {
void *Mem =
C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
LocalParameters.size(), Requirements.size()),
alignof(RequiresExpr));
- return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
- Requirements, RBraceLoc);
+ return new (Mem)
+ RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters,
+ RParenLoc, Requirements, RBraceLoc);
}
RequiresExpr *
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 53963d2a91752a8..3bbc0a5767ff49d 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -234,6 +234,11 @@ class CXXNameMangler {
const NamedDecl *Structor;
unsigned StructorType = 0;
+ // An offset to add to all template parameter depths while mangling. Used
+ // when mangling a template parameter list to see if it matches a template
+ // template parameter exactly.
+ unsigned TemplateDepthOffset = 0;
+
/// The next substitution sequence number.
unsigned SeqID = 0;
@@ -392,6 +397,10 @@ class CXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
+ bool isCompatibleWith(LangOptions::ClangABI Ver) {
+ return Context.getASTContext().getLangOpts().getClangABICompat() <= Ver;
+ }
+
bool isStd(const NamespaceDecl *NS);
bool isStdNamespace(const DeclContext *DC);
@@ -434,6 +443,13 @@ class CXXNameMangler {
NullOut = true;
}
+ struct WithTemplateDepthOffset { unsigned Offset; };
+ CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out,
+ WithTemplateDepthOffset Offset)
+ : CXXNameMangler(C, Out) {
+ TemplateDepthOffset = Offset.Offset;
+ }
+
raw_ostream &getStream() { return Out; }
void disableDerivedAbiTags() { DisableDerivedAbiTags = true; }
@@ -517,6 +533,11 @@ class CXXNameMangler {
void mangleBlockForPrefix(const BlockDecl *Block);
void mangleUnqualifiedBlock(const BlockDecl *Block);
void mangleTemplateParamDecl(const NamedDecl *Decl);
+ void mangleTemplateParameterList(const TemplateParameterList *Params);
+ void mangleTypeConstraint(const ConceptDecl *Concept,
+ ArrayRef<TemplateArgument> Arguments);
+ void mangleTypeConstraint(const TypeConstraint *Constraint);
+ void mangleRequiresClause(const Expr *RequiresClause);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(GlobalDecl GD, const DeclContext *DC,
const AbiTagList *AdditionalAbiTags,
@@ -580,16 +601,21 @@ class CXXNameMangler {
unsigned knownArity);
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
void mangleInitListElements(const InitListExpr *InitList);
+ void mangleRequirement(SourceLocation RequiresExprLoc,
+ const concepts::Requirement *Req);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity,
bool AsTemplateArg = false);
void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
void mangleCXXDtorType(CXXDtorType T);
+ struct TemplateArgManglingInfo;
void mangleTemplateArgs(TemplateName TN,
const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs);
void mangleTemplateArgs(TemplateName TN, ArrayRef<TemplateArgument> Args);
void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL);
+ void mangleTemplateArg(TemplateArgManglingInfo &Info, unsigned Index,
+ TemplateArgument A);
void mangleTemplateArg(TemplateArgument A, bool NeedExactType);
void mangleTemplateArgExpr(const Expr *E);
void mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel,
@@ -667,9 +693,16 @@ ItaniumMangleContextImpl::getEffectiveDeclContext(const Decl *D) {
if (VD->isExternC())
return getASTContext().getTranslationUnitDecl();
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isExternC())
return getASTContext().getTranslationUnitDecl();
+ // Member-like constrained friends are mangled as if they were members of
+ // the enclosing class.
+ if (FD->isMemberLikeConstrainedFriend() &&
+ getASTContext().getLangOpts().getClangABICompat() >
+ LangOptions::ClangABI::Ver17)
+ return D->getLexicalDeclContext()->getRedeclContext();
+ }
return DC->getRedeclContext();
}
@@ -858,16 +891,15 @@ void CXXNameMangler::mangleFunctionEncodingBareType(const FunctionDecl *FD) {
EnableIfAttr *EIA = dyn_cast<EnableIfAttr>(*I);
if (!EIA)
continue;
- if (Context.getASTContext().getLangOpts().getClangABICompat() >
- LangOptions::ClangABI::Ver11) {
- mangleTemplateArgExpr(EIA->getCond());
- } else {
+ if (isCompatibleWith(LangOptions::ClangABI::Ver11)) {
// Prior to Clang 12, we hardcoded the X/E around enable-if's argument,
// even though <template-arg> should not include an X/E around
// <expr-primary>.
Out << 'X';
mangleExpression(EIA->getCond());
Out << 'E';
+ } else {
+ mangleTemplateArgExpr(EIA->getCond());
}
}
Out << 'E';
@@ -1415,14 +1447,24 @@ void CXXNameMangler::mangleUnqualifiedName(
GlobalDecl GD, DeclarationName Name, const DeclContext *DC,
unsigned KnownArity, const AbiTagList *AdditionalAbiTags) {
const NamedDecl *ND = cast_or_null<NamedDecl>(GD.getDecl());
- // <unqualified-name> ::= [<module-name>] <operator-name>
+ // <unqualified-name> ::= [<module-name>] [F] <operator-name>
// ::= <ctor-dtor-name>
- // ::= [<module-name>] <source-name>
+ // ::= [<module-name>] [F] <source-name>
// ::= [<module-name>] DC <source-name>* E
if (ND && DC && DC->isFileContext())
mangleModuleName(ND);
+ // A member-like constrained friend is mangled with a leading 'F'.
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ auto *FD = dyn_cast<FunctionDecl>(ND);
+ auto *FTD = dyn_cast<FunctionTemplateDecl>(ND);
+ if ((FD && FD->isMemberLikeConstrainedFriend()) ||
+ (FTD && FTD->getTemplatedDecl()->isMemberLikeConstrainedFriend())) {
+ if (!isCompatibleWith(LangOptions::ClangABI::Ver17))
+ Out << 'F';
+ }
+
unsigned Arity = KnownArity;
switch (Name.getNameKind()) {
case DeclarationName::Identifier: {
@@ -1478,7 +1520,6 @@ void CXXNameMangler::mangleUnqualifiedName(
if (Context.isInternalLinkageDecl(ND))
Out << 'L';
- auto *FD = dyn_cast<FunctionDecl>(ND);
bool IsRegCall = FD &&
FD->getType()->castAs<FunctionType>()->getCallConv() ==
clang::CC_X86RegCall;
@@ -1911,8 +1952,7 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
// When trying to be ABI-compatibility with clang 12 and before, mangle a
// <data-member-prefix> now, with no substitutions and no <template-args>.
if (Decl *Context = Block->getBlockManglingContextDecl()) {
- if (getASTContext().getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver12 &&
+ if (isCompatibleWith(LangOptions::ClangABI::Ver12) &&
(isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
Context->getDeclContext()->isRecord()) {
const auto *ND = cast<NamedDecl>(Context);
@@ -1940,15 +1980,25 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
}
// <template-param-decl>
-// ::= Ty # template type parameter
-// ::= Tn <type> # template non-type parameter
-// ::= Tt <template-param-decl>* E # template template parameter
-// ::= Tp <template-param-decl> # template parameter pack
+// ::= Ty # template type parameter
+// ::= Tk <concept name> [<template-args>] # constrained type parameter
+// ::= Tn <type> # template non-type parameter
+// ::= Tt <template-param-decl>* E [Q <requires-clause expr>]
+// # template template parameter
+// ::= Tp <template-param-decl> # template parameter pack
void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
if (auto *Ty = dyn_cast<TemplateTypeParmDecl>(Decl)) {
if (Ty->isParameterPack())
Out << "Tp";
- Out << "Ty";
+ const TypeConstraint *Constraint = Ty->getTypeConstraint();
+ if (Constraint && !isCompatibleWith(LangOptions::ClangABI::Ver17)) {
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ Out << "Tk";
+ mangleTypeConstraint(Constraint);
+ } else {
+ Out << "Ty";
+ }
} else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
if (Tn->isExpandedParameterPack()) {
for (unsigned I = 0, N = Tn->getNumExpansionTypes(); I != N; ++I) {
@@ -1968,29 +2018,59 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
} else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
if (Tt->isExpandedParameterPack()) {
for (unsigned I = 0, N = Tt->getNumExpansionTemplateParameters(); I != N;
- ++I) {
- Out << "Tt";
- for (auto *Param : *Tt->getExpansionTemplateParameters(I))
- mangleTemplateParamDecl(Param);
- Out << "E";
- }
+ ++I)
+ mangleTemplateParameterList(Tt->getExpansionTemplateParameters(I));
} else {
if (Tt->isParameterPack())
Out << "Tp";
- Out << "Tt";
- for (auto *Param : *Tt->getTemplateParameters())
- mangleTemplateParamDecl(Param);
- Out << "E";
+ mangleTemplateParameterList(Tt->getTemplateParameters());
}
}
}
+void CXXNameMangler::mangleTemplateParameterList(
+ const TemplateParameterList *Params) {
+ Out << "Tt";
+ for (auto *Param : *Params)
+ mangleTemplateParamDecl(Param);
+ mangleRequiresClause(Params->getRequiresClause());
+ Out << "E";
+}
+
+void CXXNameMangler::mangleTypeConstraint(
+ const ConceptDecl *Concept, ArrayRef<TemplateArgument> Arguments) {
+ const DeclContext *DC = Context.getEffectiveDeclContext(Concept);
+ if (!Arguments.empty())
+ mangleTemplateName(Concept, Arguments);
+ else if (DC->isTranslationUnit() || isStdNamespace(DC))
+ mangleUnscopedName(Concept, DC, nullptr);
+ else
+ mangleNestedName(Concept, DC, nullptr);
+}
+
+void CXXNameMangler::mangleTypeConstraint(const TypeConstraint *Constraint) {
+ llvm::SmallVector<TemplateArgument, 8> Args;
+ if (Constraint->getTemplateArgsAsWritten()) {
+ for (const TemplateArgumentLoc &ArgLoc :
+ Constraint->getTemplateArgsAsWritten()->arguments())
+ Args.push_back(ArgLoc.getArgument());
+ }
+ return mangleTypeConstraint(Constraint->getNamedConcept(), Args);
+}
+
+void CXXNameMangler::mangleRequiresClause(const Expr *RequiresClause) {
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ if (RequiresClause && !isCompatibleWith(LangOptions::ClangABI::Ver17)) {
+ Out << 'Q';
+ mangleExpression(RequiresClause);
+ }
+}
+
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// When trying to be ABI-compatibility with clang 12 and before, mangle a
// <data-member-prefix> now, with no substitutions.
if (Decl *Context = Lambda->getLambdaContextDecl()) {
- if (getASTContext().getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver12 &&
+ if (isCompatibleWith(LangOptions::ClangABI::Ver12) &&
(isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
!isa<ParmVarDecl>(Context)) {
if (const IdentifierInfo *Name
@@ -2031,8 +2111,14 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
}
void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) {
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/31.
for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
mangleTemplateParamDecl(D);
+
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ if (auto *TPL = Lambda->getGenericLambdaTemplateParameterList())
+ mangleRequiresClause(TPL->getRequiresClause());
+
auto *Proto =
Lambda->getLambdaTypeInfo()->getType()->castAs<FunctionProtoType>();
mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
@@ -2063,8 +2149,7 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
case NestedNameSpecifier::Identifier:
// Clang 14 and before did not consider this substitutable.
- bool Clang14Compat = getASTContext().getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver14;
+ bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14);
if (!Clang14Compat && mangleSubstitution(qualifier))
return;
@@ -2134,8 +2219,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
// Clang 11 and before mangled the substitution for a dependent template name
// after already having emitted (a substitution for) the prefix.
- bool Clang11Compat = getASTContext().getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver11;
+ bool Clang11Compat = isCompatibleWith(LangOptions::ClangABI::Ver11);
if (!Clang11Compat && mangleSubstitution(Template))
return;
@@ -2182,8 +2266,7 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
}
const NamedDecl *CXXNameMangler::getClosurePrefix(const Decl *ND) {
- if (getASTContext().getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver12)
+ if (isCompatibleWith(LangOptions::ClangABI::Ver12))
return nullptr;
const NamedDecl *Context = nullptr;
@@ -3430,39 +3513,42 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionProtoType *Proto,
if (Proto->getNumParams() == 0 && !Proto->isVariadic()) {
// <builtin-type> ::= v # void
Out << 'v';
+ } else {
+ assert(!FD || FD->getNumParams() == Proto->getNumParams());
+ for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
+ // Mangle extended parameter info as order-sensitive qualifiers here.
+ if (Proto->hasExtParameterInfos() && FD == nullptr) {
+ mangleExtParameterInfo(Proto->getExtParameterInfo(I));
+ }
- FunctionTypeDepth.pop(saved);
- return;
- }
-
- assert(!FD || FD->getNumParams() == Proto->getNumParams());
- for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) {
- // Mangle extended parameter info as order-sensitive qualifiers here.
- if (Proto->hasExtParameterInfos() && FD == nullptr) {
- mangleExtParameterInfo(Proto->getExtParameterInfo(I));
+ // Mangle the type.
+ QualType ParamTy = Proto->getParamType(I);
+ mangleType(Context.getASTContext().getSignatureParameterType(ParamTy));
+
+ if (FD) {
+ if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) {
+ // Attr can only take 1 character, so we can hardcode the length
+ // below.
+ assert(Attr->getType() <= 9 && Attr->getType() >= 0);
+ if (Attr->isDynamic())
+ Out << "U25pass_dynamic_object_size" << Attr->getType();
+ else
+ Out << "U17pass_object_size" << Attr->getType();
+ }
+ }
}
- // Mangle the type.
- QualType ParamTy = Proto->getParamType(I);
- mangleType(Context.getASTContext().getSignatureParameterType(ParamTy));
+ // <builtin-type> ::= z # ellipsis
+ if (Proto->isVariadic())
+ Out << 'z';
+ }
- if (FD) {
- if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) {
- // Attr can only take 1 character, so we can hardcode the length below.
- assert(Attr->getType() <= 9 && Attr->getType() >= 0);
- if (Attr->isDynamic())
- Out << "U25pass_dynamic_object_size" << Attr->getType();
- else
- Out << "U17pass_object_size" << Attr->getType();
- }
- }
+ if (FD) {
+ FunctionTypeDepth.enterResultType();
+ mangleRequiresClause(FD->getTrailingRequiresClause());
}
FunctionTypeDepth.pop(saved);
-
- // <builtin-type> ::= z # ellipsis
- if (Proto->isVariadic())
- Out << 'z';
}
// <type> ::= <class-enum-type>
@@ -4198,7 +4284,15 @@ void CXXNameMangler::mangleType(const AutoType *T) {
"shouldn't need to mangle __auto_type!");
// <builtin-type> ::= Da # auto
// ::= Dc # decltype(auto)
- Out << (T->isDecltypeAuto() ? "Dc" : "Da");
+ // ::= Dk # constrained auto
+ // ::= DK # constrained decltype(auto)
+ if (T->isConstrained() && !isCompatibleWith(LangOptions::ClangABI::Ver17)) {
+ Out << (T->isDecltypeAuto() ? "DK" : "Dk");
+ mangleTypeConstraint(T->getTypeConstraintConcept(),
+ T->getTypeConstraintArguments());
+ } else {
+ Out << (T->isDecltypeAuto() ? "Dc" : "Da");
+ }
}
void CXXNameMangler::mangleType(const DeducedTemplateSpecializationType *T) {
@@ -4346,6 +4440,74 @@ void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) {
mangleExpression(InitList->getInit(i));
}
+void CXXNameMangler::mangleRequirement(SourceLocation RequiresExprLoc,
+ const concepts::Requirement *Req) {
+ using concepts::Requirement;
+
+ // TODO: We can't mangle the result of a failed substitution. It's not clear
+ // whether we should be mangling the original form prior to any substitution
+ // instead. See https://lists.isocpp.org/core/2023/04/14118.php
+ auto HandleSubstitutionFailure =
+ [&](SourceLocation Loc) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "cannot mangle this requires-expression "
+ "containing a substitution failure");
+ Diags.Report(Loc, DiagID);
+ Out << 'F';
+ };
+
+ switch (Req->getKind()) {
+ case Requirement::RK_Type: {
+ const auto *TR = cast<concepts::TypeRequirement>(Req);
+ if (TR->isSubstitutionFailure())
+ return HandleSubstitutionFailure(
+ TR->getSubstitutionDiagnostic()->DiagLoc);
+
+ Out << 'T';
+ mangleType(TR->getType()->getType());
+ break;
+ }
+
+ case Requirement::RK_Simple:
+ case Requirement::RK_Compound: {
+ const auto *ER = cast<concepts::ExprRequirement>(Req);
+ if (ER->isExprSubstitutionFailure())
+ return HandleSubstitutionFailure(
+ ER->getExprSubstitutionDiagnostic()->DiagLoc);
+
+ Out << 'X';
+ mangleExpression(ER->getExpr());
+
+ if (ER->hasNoexceptRequirement())
+ Out << 'N';
+
+ if (!ER->getReturnTypeRequirement().isEmpty()) {
+ if (ER->getReturnTypeRequirement().isSubstitutionFailure())
+ return HandleSubstitutionFailure(ER->getReturnTypeRequirement()
+ .getSubstitutionDiagnostic()
+ ->DiagLoc);
+
+ Out << 'R';
+ mangleTypeConstraint(ER->getReturnTypeRequirement().getTypeConstraint());
+ }
+ break;
+ }
+
+ case Requirement::RK_Nested:
+ const auto *NR = cast<concepts::NestedRequirement>(Req);
+ if (NR->hasInvalidConstraint()) {
+ // FIXME: NestedRequirement should track the location of its requires
+ // keyword.
+ return HandleSubstitutionFailure(RequiresExprLoc);
+ }
+
+ Out << 'Q';
+ mangleExpression(NR->getConstraintExpr());
+ break;
+ }
+}
+
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
bool AsTemplateArg) {
// <expression> ::= <unary operator-name> <expression>
@@ -4479,7 +4641,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
case Expr::ConvertVectorExprClass:
case Expr::StmtExprClass:
case Expr::TypeTraitExprClass:
- case Expr::RequiresExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
@@ -4508,8 +4669,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
const CXXUuidofExpr *UE = cast<CXXUuidofExpr>(E);
// As of clang 12, uuidof uses the vendor extended expression
// mangling. Previously, it used a special-cased nonstandard extension.
- if (Context.getASTContext().getLangOpts().getClangABICompat() >
- LangOptions::ClangABI::Ver11) {
+ if (!isCompatibleWith(LangOptions::ClangABI::Ver11)) {
Out << "u8__uuidof";
if (UE->isTypeOperand())
mangleType(UE->getTypeOperand(Context.getASTContext()));
@@ -4861,8 +5021,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
// As of clang 12, we mangle __alignof__
diff erently than alignof. (They
// have acted
diff erently since Clang 8, but were previously mangled the
// same.)
- if (Context.getASTContext().getLangOpts().getClangABICompat() >
- LangOptions::ClangABI::Ver11) {
+ if (!isCompatibleWith(LangOptions::ClangABI::Ver11)) {
Out << "u11__alignof__";
if (SAE->isArgumentType())
mangleType(SAE->getArgumentType());
@@ -5083,11 +5242,57 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
goto recurse;
case Expr::ConceptSpecializationExprClass: {
- // <expr-primary> ::= L <mangled-name> E # external name
- Out << "L_Z";
auto *CSE = cast<ConceptSpecializationExpr>(E);
- mangleTemplateName(CSE->getNamedConcept(), CSE->getTemplateArguments());
- Out << 'E';
+ if (isCompatibleWith(LangOptions::ClangABI::Ver17)) {
+ // Clang 17 and before mangled concept-ids as if they resolved to an
+ // entity, meaning that references to enclosing template arguments don't
+ // work.
+ Out << "L_Z";
+ mangleTemplateName(CSE->getNamedConcept(), CSE->getTemplateArguments());
+ Out << 'E';
+ break;
+ }
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ NotPrimaryExpr();
+ mangleUnresolvedName(
+ CSE->getNestedNameSpecifierLoc().getNestedNameSpecifier(),
+ CSE->getConceptNameInfo().getName(),
+ CSE->getTemplateArgsAsWritten()->getTemplateArgs(),
+ CSE->getTemplateArgsAsWritten()->getNumTemplateArgs());
+ break;
+ }
+
+ case Expr::RequiresExprClass: {
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ auto *RE = cast<RequiresExpr>(E);
+ // This is a primary-expression in the C++ grammar, but does not have an
+ // <expr-primary> mangling (starting with 'L').
+ NotPrimaryExpr();
+ if (RE->getLParenLoc().isValid()) {
+ Out << "rQ";
+ FunctionTypeDepthState saved = FunctionTypeDepth.push();
+ if (RE->getLocalParameters().empty()) {
+ Out << 'v';
+ } else {
+ for (ParmVarDecl *Param : RE->getLocalParameters()) {
+ mangleType(Context.getASTContext().getSignatureParameterType(
+ Param->getType()));
+ }
+ }
+ Out << '_';
+
+ // The rest of the mangling is in the immediate scope of the parameters.
+ FunctionTypeDepth.enterResultType();
+ for (const concepts::Requirement *Req : RE->getRequirements())
+ mangleRequirement(RE->getExprLoc(), Req);
+ FunctionTypeDepth.pop(saved);
+ Out << 'E';
+ } else {
+ Out << "rq";
+ for (const concepts::Requirement *Req : RE->getRequirements())
+ mangleRequirement(RE->getExprLoc(), Req);
+ Out << 'E';
+ }
break;
}
@@ -5448,28 +5653,116 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
}
}
-namespace {
// Helper to provide ancillary information on a template used to mangle its
// arguments.
-struct TemplateArgManglingInfo {
+struct CXXNameMangler::TemplateArgManglingInfo {
+ const CXXNameMangler &Mangler;
TemplateDecl *ResolvedTemplate = nullptr;
bool SeenPackExpansionIntoNonPack = false;
const NamedDecl *UnresolvedExpandedPack = nullptr;
- TemplateArgManglingInfo(TemplateName TN) {
+ TemplateArgManglingInfo(const CXXNameMangler &Mangler, TemplateName TN)
+ : Mangler(Mangler) {
if (TemplateDecl *TD = TN.getAsTemplateDecl())
ResolvedTemplate = TD;
}
- /// Do we need to mangle template arguments with exactly correct types?
- ///
+ /// Information about how to mangle a template argument.
+ struct Info {
+ /// Do we need to mangle the template argument with an exactly correct type?
+ bool NeedExactType;
+ /// If we need to prefix the mangling with a mangling of the template
+ /// parameter, the corresponding parameter.
+ const NamedDecl *TemplateParameterToMangle;
+ };
+
+ /// Determine whether the resolved template might be overloaded on its
+ /// template parameter list. If so, the mangling needs to include enough
+ /// information to reconstruct the template parameter list.
+ bool isOverloadable() {
+ // Function templates are generally overloadable. As a special case, a
+ // member function template of a generic lambda is not overloadable.
+ if (auto *FTD = dyn_cast_or_null<FunctionTemplateDecl>(ResolvedTemplate)) {
+ auto *RD = dyn_cast<CXXRecordDecl>(FTD->getDeclContext());
+ if (!RD || !RD->isGenericLambda())
+ return true;
+ }
+
+ // All other templates are not overloadable. Partial specializations would
+ // be, but we never mangle them.
+ return false;
+ }
+
+ /// Determine whether we need to prefix this <template-arg> mangling with a
+ /// <template-param-decl>. This happens if the natural template parameter for
+ /// the argument mangling is not the same as the actual template parameter.
+ bool needToMangleTemplateParam(const NamedDecl *Param,
+ const TemplateArgument &Arg) {
+ // For a template type parameter, the natural parameter is 'typename T'.
+ // The actual parameter might be constrained.
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ return TTP->hasTypeConstraint();
+
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ // For an empty pack, the natural parameter is `typename...`.
+ if (Arg.pack_size() == 0)
+ return true;
+
+ // For any other pack, we use the first argument to determine the natural
+ // template parameter.
+ return needToMangleTemplateParam(Param, *Arg.pack_begin());
+ }
+
+ // For a non-type template parameter, the natural parameter is `T V` (for a
+ // prvalue argument) or `T &V` (for a glvalue argument), where `T` is the
+ // type of the argument, which we require to exactly match. If the actual
+ // parameter has a deduced or instantiation-dependent type, it is not
+ // equivalent to the natural parameter.
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ return NTTP->getType()->isInstantiationDependentType() ||
+ NTTP->getType()->getContainedDeducedType();
+
+ // For a template template parameter, the template-head might
diff er from
+ // that of the template.
+ auto *TTP = cast<TemplateTemplateParmDecl>(Param);
+ TemplateName ArgTemplateName = Arg.getAsTemplateOrTemplatePattern();
+ const TemplateDecl *ArgTemplate = ArgTemplateName.getAsTemplateDecl();
+ if (!ArgTemplate)
+ return true;
+
+ // Mangle the template parameter list of the parameter and argument to see
+ // if they are the same. We can't use Profile for this, because it can't
+ // model the depth
diff erence between parameter and argument and might not
+ // necessarily have the same definition of "identical" that we use here --
+ // that is, same mangling.
+ auto MangleTemplateParamListToString =
+ [&](SmallVectorImpl<char> &Buffer, const TemplateParameterList *Params,
+ unsigned DepthOffset) {
+ llvm::raw_svector_ostream Stream(Buffer);
+ CXXNameMangler(Mangler.Context, Stream,
+ WithTemplateDepthOffset{DepthOffset})
+ .mangleTemplateParameterList(Params);
+ };
+ llvm::SmallString<128> ParamTemplateHead, ArgTemplateHead;
+ MangleTemplateParamListToString(ParamTemplateHead,
+ TTP->getTemplateParameters(), 0);
+ // Add the depth of the parameter's template parameter list to all
+ // parameters appearing in the argument to make the indexes line up
+ // properly.
+ MangleTemplateParamListToString(ArgTemplateHead,
+ ArgTemplate->getTemplateParameters(),
+ TTP->getTemplateParameters()->getDepth());
+ return ParamTemplateHead != ArgTemplateHead;
+ }
+
+ /// Determine information about how this template argument should be mangled.
/// This should be called exactly once for each parameter / argument pair, in
/// order.
- bool needExactType(unsigned ParamIdx, const TemplateArgument &Arg) {
+ Info getArgInfo(unsigned ParamIdx, const TemplateArgument &Arg) {
// We need correct types when the template-name is unresolved or when it
// names a template that is able to be overloaded.
if (!ResolvedTemplate || SeenPackExpansionIntoNonPack)
- return true;
+ return {true, nullptr};
// Move to the next parameter.
const NamedDecl *Param = UnresolvedExpandedPack;
@@ -5495,17 +5788,13 @@ struct TemplateArgManglingInfo {
if (Arg.isPackExpansion() &&
(!Param->isParameterPack() || UnresolvedExpandedPack)) {
SeenPackExpansionIntoNonPack = true;
- return true;
+ return {true, nullptr};
}
- // We need exact types for function template arguments because they might be
- // overloaded on template parameter type. As a special case, a member
- // function template of a generic lambda is not overloadable.
- if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ResolvedTemplate)) {
- auto *RD = dyn_cast<CXXRecordDecl>(FTD->getDeclContext());
- if (!RD || !RD->isGenericLambda())
- return true;
- }
+ // We need exact types for arguments of a template that might be overloaded
+ // on template parameter type.
+ if (isOverloadable())
+ return {true, needToMangleTemplateParam(Param, Arg) ? Param : nullptr};
// Otherwise, we only need a correct type if the parameter has a deduced
// type.
@@ -5515,43 +5804,75 @@ struct TemplateArgManglingInfo {
// but it doesn't matter because substitution and expansion don't affect
// whether a deduced type appears in the type.
auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param);
- return NTTP && NTTP->getType()->getContainedDeducedType();
+ bool NeedExactType = NTTP && NTTP->getType()->getContainedDeducedType();
+ return {NeedExactType, nullptr};
+ }
+
+ /// Determine if we should mangle a requires-clause after the template
+ /// argument list. If so, returns the expression to mangle.
+ const Expr *getTrailingRequiresClauseToMangle() {
+ if (!isOverloadable())
+ return nullptr;
+ return ResolvedTemplate->getTemplateParameters()->getRequiresClause();
}
};
-}
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs) {
- // <template-args> ::= I <template-arg>+ E
+ // <template-args> ::= I <template-arg>+ [Q <requires-clause expr>] E
Out << 'I';
- TemplateArgManglingInfo Info(TN);
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(TemplateArgs[i].getArgument(),
- Info.needExactType(i, TemplateArgs[i].getArgument()));
+ TemplateArgManglingInfo Info(*this, TN);
+ for (unsigned i = 0; i != NumTemplateArgs; ++i) {
+ mangleTemplateArg(Info, i, TemplateArgs[i].getArgument());
+ }
+ mangleRequiresClause(Info.getTrailingRequiresClauseToMangle());
Out << 'E';
}
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
const TemplateArgumentList &AL) {
- // <template-args> ::= I <template-arg>+ E
+ // <template-args> ::= I <template-arg>+ [Q <requires-clause expr>] E
Out << 'I';
- TemplateArgManglingInfo Info(TN);
- for (unsigned i = 0, e = AL.size(); i != e; ++i)
- mangleTemplateArg(AL[i], Info.needExactType(i, AL[i]));
+ TemplateArgManglingInfo Info(*this, TN);
+ for (unsigned i = 0, e = AL.size(); i != e; ++i) {
+ mangleTemplateArg(Info, i, AL[i]);
+ }
+ mangleRequiresClause(Info.getTrailingRequiresClauseToMangle());
Out << 'E';
}
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
ArrayRef<TemplateArgument> Args) {
- // <template-args> ::= I <template-arg>+ E
+ // <template-args> ::= I <template-arg>+ [Q <requires-clause expr>] E
Out << 'I';
- TemplateArgManglingInfo Info(TN);
- for (unsigned i = 0; i != Args.size(); ++i)
- mangleTemplateArg(Args[i], Info.needExactType(i, Args[i]));
+ TemplateArgManglingInfo Info(*this, TN);
+ for (unsigned i = 0; i != Args.size(); ++i) {
+ mangleTemplateArg(Info, i, Args[i]);
+ }
+ mangleRequiresClause(Info.getTrailingRequiresClauseToMangle());
Out << 'E';
}
+void CXXNameMangler::mangleTemplateArg(TemplateArgManglingInfo &Info,
+ unsigned Index, TemplateArgument A) {
+ TemplateArgManglingInfo::Info ArgInfo = Info.getArgInfo(Index, A);
+
+ // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/47.
+ if (ArgInfo.TemplateParameterToMangle &&
+ !isCompatibleWith(LangOptions::ClangABI::Ver17)) {
+ // The template parameter is mangled if the mangling would otherwise be
+ // ambiguous.
+ //
+ // <template-arg> ::= <template-param-decl> <template-arg>
+ //
+ // Clang 17 and before did not do this.
+ mangleTemplateParamDecl(ArgInfo.TemplateParameterToMangle);
+ }
+
+ mangleTemplateArg(A, ArgInfo.NeedExactType);
+}
+
void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
@@ -5604,8 +5925,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
else if (D->getType()->isArrayType() &&
Ctx.hasSimilarType(Ctx.getDecayedType(D->getType()),
A.getParamTypeForDecl()) &&
- Ctx.getLangOpts().getClangABICompat() >
- LangOptions::ClangABI::Ver11)
+ !isCompatibleWith(LangOptions::ClangABI::Ver11))
// Build a value corresponding to this implicit array-to-pointer decay.
Value = APValue(APValue::LValueBase(D), CharUnits::Zero(),
{APValue::LValuePathEntry::ArrayIndex(0)},
@@ -5634,8 +5954,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
}
void CXXNameMangler::mangleTemplateArgExpr(const Expr *E) {
- ASTContext &Ctx = Context.getASTContext();
- if (Ctx.getLangOpts().getClangABICompat() > LangOptions::ClangABI::Ver11) {
+ if (!isCompatibleWith(LangOptions::ClangABI::Ver11)) {
mangleExpression(E, UnknownArity, /*AsTemplateArg=*/true);
return;
}
@@ -6051,8 +6370,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
} else {
if (NeedExactType &&
!Ctx.hasSameType(T->getPointeeType(), getLValueType(Ctx, V)) &&
- Ctx.getLangOpts().getClangABICompat() >
- LangOptions::ClangABI::Ver11) {
+ !isCompatibleWith(LangOptions::ClangABI::Ver11)) {
NotPrimaryExpr();
Out << "cv";
mangleType(T);
@@ -6150,8 +6468,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
!Ctx.hasSameType(
T->castAs<MemberPointerType>()->getPointeeType(),
V.getMemberPointerDecl()->getType()) &&
- Ctx.getLangOpts().getClangABICompat() >
- LangOptions::ClangABI::Ver11) {
+ !isCompatibleWith(LangOptions::ClangABI::Ver11)) {
Out << "cv";
mangleType(T);
}
@@ -6182,6 +6499,7 @@ void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
// The latter two manglings are from a proposal here:
// https://github.com/itanium-cxx-abi/cxx-abi/issues/31#issuecomment-528122117
Out << 'T';
+ Depth += TemplateDepthOffset;
if (Depth != 0)
Out << 'L' << (Depth - 1) << '_';
if (Index != 0)
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index ffb4f30db0243ec..9293b910c57d6c3 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3549,24 +3549,40 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
for (const std::string &F : Opts.NoSanitizeFiles)
GenerateArg(Consumer, OPT_fsanitize_ignorelist_EQ, F);
- if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver3_8)
+ switch (Opts.getClangABICompat()) {
+ case LangOptions::ClangABI::Ver3_8:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "3.8");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver4)
+ break;
+ case LangOptions::ClangABI::Ver4:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "4.0");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver6)
+ break;
+ case LangOptions::ClangABI::Ver6:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "6.0");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver7)
+ break;
+ case LangOptions::ClangABI::Ver7:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "7.0");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver9)
+ break;
+ case LangOptions::ClangABI::Ver9:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "9.0");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver11)
+ break;
+ case LangOptions::ClangABI::Ver11:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "11.0");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver12)
+ break;
+ case LangOptions::ClangABI::Ver12:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "12.0");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver14)
+ break;
+ case LangOptions::ClangABI::Ver14:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "14.0");
- else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver15)
+ break;
+ case LangOptions::ClangABI::Ver15:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "15.0");
+ break;
+ case LangOptions::ClangABI::Ver17:
+ GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "17.0");
+ break;
+ case LangOptions::ClangABI::Latest:
+ break;
+ }
if (Opts.getSignReturnAddressScope() ==
LangOptions::SignReturnAddressScopeKind::All)
@@ -4052,6 +4068,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.setClangABICompat(LangOptions::ClangABI::Ver14);
else if (Major <= 15)
Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
+ else if (Major <= 17)
+ Opts.setClangABICompat(LangOptions::ClangABI::Ver17);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index d2715db95f52851..99b4931004546c1 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -3493,11 +3493,11 @@ ExprResult Parser::ParseRequiresExpression() {
SourceLocation RequiresKWLoc = ConsumeToken(); // Consume 'requires'
llvm::SmallVector<ParmVarDecl *, 2> LocalParameterDecls;
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
if (Tok.is(tok::l_paren)) {
// requirement parameter list is present.
ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope |
Scope::DeclScope);
- BalancedDelimiterTracker Parens(*this, tok::l_paren);
Parens.consumeOpen();
if (!Tok.is(tok::r_paren)) {
ParsedAttributes FirstArgAttrs(getAttrFactory());
@@ -3769,8 +3769,9 @@ ExprResult Parser::ParseRequiresExpression() {
Braces.consumeClose();
Actions.ActOnFinishRequiresExpr();
ParsingBodyDecl.complete(Body);
- return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls,
- Requirements, Braces.getCloseLocation());
+ return Actions.ActOnRequiresExpr(
+ RequiresKWLoc, Body, Parens.getOpenLocation(), LocalParameterDecls,
+ Parens.getCloseLocation(), Requirements, Braces.getCloseLocation());
}
static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) {
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 77289595972e3cf..c147cc5293fd788 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9191,14 +9191,14 @@ void Sema::ActOnFinishRequiresExpr() {
assert(CurContext && "Popped translation unit!");
}
-ExprResult
-Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc,
- RequiresExprBodyDecl *Body,
- ArrayRef<ParmVarDecl *> LocalParameters,
- ArrayRef<concepts::Requirement *> Requirements,
- SourceLocation ClosingBraceLoc) {
- auto *RE = RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters,
- Requirements, ClosingBraceLoc);
+ExprResult Sema::ActOnRequiresExpr(
+ SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body,
+ SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters,
+ SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements,
+ SourceLocation ClosingBraceLoc) {
+ auto *RE = RequiresExpr::Create(Context, RequiresKWLoc, Body, LParenLoc,
+ LocalParameters, RParenLoc, Requirements,
+ ClosingBraceLoc);
if (DiagnoseUnexpandedParameterPackInRequiresExpr(RE))
return ExprError();
return RE;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index c723e47ffca8ecd..00a36696cf90450 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2344,8 +2344,9 @@ ExprResult TemplateInstantiator::TransformRequiresTypeParams(
// here.
TransReqs.push_back(RebuildTypeRequirement(createSubstDiag(
SemaRef, Info, [&](llvm::raw_ostream &OS) { OS << *FailedDecl; })));
- return getDerived().RebuildRequiresExpr(KWLoc, Body, TransParams, TransReqs,
- RBraceLoc);
+ return getDerived().RebuildRequiresExpr(KWLoc, Body, RE->getLParenLoc(),
+ TransParams, RE->getRParenLoc(),
+ TransReqs, RBraceLoc);
}
return ExprResult{};
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 603a23275889f21..0fc5ad8e3bde6c6 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -549,7 +549,8 @@ class TreeTransform {
DeclarationNameInfo
TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo);
- bool TransformRequiresExprRequirements(ArrayRef<concepts::Requirement *> Reqs,
+ bool TransformRequiresExprRequirements(
+ ArrayRef<concepts::Requirement *> Reqs,
llvm::SmallVectorImpl<concepts::Requirement *> &Transformed);
concepts::TypeRequirement *
TransformTypeRequirement(concepts::TypeRequirement *Req);
@@ -3616,11 +3617,14 @@ class TreeTransform {
/// Subclasses may override this routine to provide
diff erent behavior.
ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc,
RequiresExprBodyDecl *Body,
+ SourceLocation LParenLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
+ SourceLocation RParenLoc,
ArrayRef<concepts::Requirement *> Requirements,
SourceLocation ClosingBraceLoc) {
- return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body,
- LocalParameters, Requirements, ClosingBraceLoc);
+ return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body, LParenLoc,
+ LocalParameters, RParenLoc, Requirements,
+ ClosingBraceLoc);
}
concepts::TypeRequirement *
@@ -12968,9 +12972,9 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
}
}
- return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body,
- TransParams, TransReqs,
- E->getRBraceLoc());
+ return getDerived().RebuildRequiresExpr(
+ E->getRequiresKWLoc(), Body, E->getLParenLoc(), TransParams,
+ E->getRParenLoc(), TransReqs, E->getRBraceLoc());
}
template<typename Derived>
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index b9d934983929933..8edb04f4f81907e 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -920,6 +920,8 @@ void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) {
}
std::copy(Requirements.begin(), Requirements.end(),
E->getTrailingObjects<concepts::Requirement *>());
+ E->LParenLoc = Record.readSourceLocation();
+ E->RParenLoc = Record.readSourceLocation();
E->RBraceLoc = Record.readSourceLocation();
}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 94d3f9430d27a0a..125ca17c0c1212e 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -507,6 +507,8 @@ void ASTStmtWriter::VisitRequiresExpr(RequiresExpr *E) {
}
}
}
+ Record.AddSourceLocation(E->getLParenLoc());
+ Record.AddSourceLocation(E->getRParenLoc());
Record.AddSourceLocation(E->getEndLoc());
Code = serialization::EXPR_REQUIRES;
diff --git a/clang/test/CodeGenCXX/mangle-concept.cpp b/clang/test/CodeGenCXX/mangle-concept.cpp
index e60e6348a5f6d4b..dec26aeaeca464c 100644
--- a/clang/test/CodeGenCXX/mangle-concept.cpp
+++ b/clang/test/CodeGenCXX/mangle-concept.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -verify -Wno-return-type -Wno-main -std=c++2a -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
+// RUN: %clang_cc1 -verify -frelaxed-template-template-args -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
+// RUN: %clang_cc1 -verify -frelaxed-template-template-args -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=16 | FileCheck %s --check-prefix=CLANG16
// expected-no-diagnostics
namespace test1 {
@@ -6,11 +7,216 @@ template <bool> struct S {};
template <typename> concept C = true;
template <typename T = int> S<C<T>> f0() { return S<C<T>>{}; }
template S<C<int>> f0<>();
-// CHECK: @_ZN5test12f0IiEENS_1SIL_ZNS_1CIT_EEEEEv(
+// CHECK: @_ZN5test12f0IiEENS_1SIX1CIT_EEEEv(
+// CLANG16: @_ZN5test12f0IiEENS_1SIL_ZNS_1CIT_EEEEEv(
}
template <bool> struct S {};
template <typename> concept C = true;
+template <typename, typename> concept D = true;
+
+template <typename T = int> S<test1::C<T>> f0a() { return S<C<T>>{}; }
+template S<test1::C<int>> f0a<>();
+// CHECK: @_Z3f0aIiE1SIXsr5test1E1CIT_EEEv(
+// CLANG16: @_Z3f0aIiE1SIL_ZN5test11CIT_EEEEv(
+
template <typename T = int> S<C<T>> f0() { return S<C<T>>{}; }
template S<C<int>> f0<>();
-// CHECK: @_Z2f0IiE1SIL_Z1CIT_EEEv(
+// CHECK: @_Z2f0IiE1SIX1CIT_EEEv(
+// CLANG16: @_Z2f0IiE1SIL_Z1CIT_EEEv(
+
+template<typename T> concept True = true;
+
+namespace test2 {
+ // Member-like friends.
+ template<typename T> struct A {
+ friend void f(...) requires True<T> {}
+
+ template<typename U = void>
+ friend void g(...) requires True<T> && True<U> {}
+
+ template<typename U = void>
+ friend void h(...) requires True<U> {}
+
+ template<typename U = void> requires True<T> && True<U>
+ friend void i(...) {}
+
+ template<typename U = void> requires True<U>
+ friend void j(...) {}
+
+ template<True U = void> requires True<T>
+ friend void k(...) {}
+
+ template<True U = void>
+ friend void l(...) {}
+ };
+
+ A<int> ai;
+
+ // CHECK-LABEL: define {{.*}}@{{.*}}test2{{.*}}use
+ void use() {
+ // CHECK: call {{.*}}@_ZN5test21AIiEF1fEzQ4TrueIT_E(
+ // CLANG16: call {{.*}}@_ZN5test21fEz(
+ f(ai);
+ // CHECK: call {{.*}}@_ZN5test2F1gIvEEvzQaa4TrueIT_E4TrueITL0__E(
+ // CLANG16: call {{.*}}@_ZN5test21gIvEEvz(
+ g(ai);
+ // CHECK: call {{.*}}@_ZN5test21hIvEEvzQ4TrueITL0__E(
+ // CLANG16: call {{.*}}@_ZN5test21hIvEEvz(
+ h(ai);
+ // CHECK: call {{.*}}@_ZN5test2F1iIvQaa4TrueIT_E4TrueITL0__EEEvz(
+ // CLANG16: call {{.*}}@_ZN5test21iIvEEvz(
+ i(ai);
+ // CHECK: call {{.*}}@_ZN5test21jIvQ4TrueITL0__EEEvz(
+ // CLANG16: call {{.*}}@_ZN5test21jIvEEvz(
+ j(ai);
+ // CHECK: call {{.*}}@_ZN5test2F1kITk4TruevQ4TrueIT_EEEvz(
+ // CLANG16: call {{.*}}@_ZN5test21kIvEEvz(
+ k(ai);
+ // CHECK: call {{.*}}@_ZN5test21lITk4TruevEEvz(
+ // CLANG16: call {{.*}}@_ZN5test21lIvEEvz(
+ l(ai);
+ }
+}
+
+namespace test3 {
+ // Unconstrained auto.
+ template<auto> void d() {}
+ template void d<0>();
+ // CHECK: define {{.*}}@_ZN5test31dITnDaLi0EEEvv(
+ // CLANG16: define {{.*}}@_ZN5test31dILi0EEEvv(
+
+ template<decltype(auto)> void e() {}
+ template void e<0>();
+ // CHECK: define {{.*}}@_ZN5test31eITnDcLi0EEEvv(
+ // CLANG16: define {{.*}}@_ZN5test31eILi0EEEvv(
+
+ // Constrained auto.
+ template<C auto> void f() {}
+ template void f<0>();
+ // CHECK: define {{.*}}@_ZN5test31fITnDk1CLi0EEEvv(
+ // CLANG16: define {{.*}}@_ZN5test31fILi0EEEvv(
+
+ template<D<int> auto> void g() {}
+ template void g<0>();
+ // CHECK: define {{.*}}@_ZN5test31gITnDk1DIiELi0EEEvv(
+ // CLANG16: define {{.*}}@_ZN5test31gILi0EEEvv(
+
+ template<typename T, D<T> auto> void h() {}
+ template void h<int, 0>();
+ // CHECK: define {{.*}}@_ZN5test31hIiTnDk1DIT_ELi0EEEvv(
+ // CLANG16: define {{.*}}@_ZN5test31hIiLi0EEEvv(
+
+ template<typename T> void i(decltype(new C auto(T()))) {}
+ template void i<int>(int*);
+ // CHECK: define {{.*}}@_ZN5test31iIiEEvDTnw_Dk1CpicvT__EEE(
+ // CLANG16: define {{.*}}@_ZN5test31iIiEEvDTnw_DapicvT__EEE(
+
+ template<typename T> void j(decltype(new C decltype(auto)(T()))) {}
+ template void j<int>(int*);
+ // CHECK: define {{.*}}@_ZN5test31jIiEEvDTnw_DK1CpicvT__EEE(
+ // CLANG16: define {{.*}}@_ZN5test31jIiEEvDTnw_DcpicvT__EEE(
+}
+
+namespace test4 {
+ // Constrained type parameters.
+ template<C> void f() {}
+ template void f<int>();
+ // CHECK: define {{.*}}@_ZN5test41fITk1CiEEvv(
+ // CLANG16: define {{.*}}@_ZN5test41fIiEEvv(
+
+ template<D<int>> void g() {}
+ template void g<int>();
+ // CHECK: define {{.*}}@_ZN5test41gITk1DIiEiEEvv(
+ // CLANG16: define {{.*}}@_ZN5test41gIiEEvv(
+}
+
+namespace test5 {
+ // Exact-match vs non-exact-match template template parameters.
+ template<typename T, T V> struct X {};
+ template<typename T, T V> requires C<T> struct Y {};
+ template<C T, T V> struct Z {};
+
+ template<template<typename T, T> typename> void f() {}
+ // CHECK: define {{.*}}@_ZN5test51fINS_1XEEEvv(
+ template void f<X>();
+ // CHECK: define {{.*}}@_ZN5test51fITtTyTnTL0__ENS_1YEEEvv(
+ template void f<Y>();
+ // CHECK: define {{.*}}@_ZN5test51fITtTyTnTL0__ENS_1ZEEEvv(
+ template void f<Z>();
+
+ template<template<typename T, T> requires C<T> typename> void g() {}
+ // CHECK: define {{.*}}@_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1XEEEvv(
+ template void g<X>();
+ // CHECK: define {{.*}}@_ZN5test51gINS_1YEEEvv(
+ template void g<Y>();
+ // CHECK: define {{.*}}@_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1ZEEEvv(
+ template void g<Z>();
+
+ template<template<C T, T> typename> void h() {}
+ // CHECK: define {{.*}}@_ZN5test51hITtTk1CTnTL0__ENS_1XEEEvv(
+ template void h<X>();
+ // CHECK: define {{.*}}@_ZN5test51hITtTk1CTnTL0__ENS_1YEEEvv(
+ template void h<Y>();
+ // CHECK: define {{.*}}@_ZN5test51hINS_1ZEEEvv(
+ template void h<Z>();
+
+ // Packs must match the first argument.
+ template<template<C T, T> typename...> void i() {}
+ // CHECK: define {{.*}}@_ZN5test51iITpTtTk1CTnTL0__EJNS_1XENS_1YENS_1ZEEEEvv(
+ template void i<X, Y, Z>();
+ // CHECK: define {{.*}}@_ZN5test51iITpTtTk1CTnTL0__EJNS_1YENS_1ZENS_1XEEEEvv(
+ template void i<Y, Z, X>();
+ // CHECK: define {{.*}}@_ZN5test51iIJNS_1ZENS_1XENS_1YEEEEvv(
+ template void i<Z, X, Y>();
+
+ template<typename ...T> struct A {};
+ template<typename, typename> struct B {};
+
+ template<template<typename ...> typename> void p() {}
+ // CHECK: define {{.*}}@_ZN5test51pINS_1AEEEvv(
+ // CLANG16: define {{.*}}@_ZN5test51pINS_1AEEEvv(
+ template void p<A>();
+ // CHECK: define {{.*}}@_ZN5test51pITtTpTyENS_1BEEEvv(
+ // CLANG16: define {{.*}}@_ZN5test51pINS_1BEEEvv(
+ template void p<B>();
+
+ template<template<typename, typename> typename> void q() {}
+ // CHECK: define {{.*}}@_ZN5test51qITtTyTyENS_1AEEEvv(
+ // CLANG16: define {{.*}}@_ZN5test51qINS_1AEEEvv(
+ template void q<A>();
+ // CHECK: define {{.*}}@_ZN5test51qINS_1BEEEvv(
+ // CLANG16: define {{.*}}@_ZN5test51qINS_1BEEEvv(
+ template void q<B>();
+}
+
+namespace test6 {
+ // Abbreviated function templates.
+ void f(C auto) {}
+ // CHECK: define {{.*}}@_ZN5test61fITk1CiEEvT_(
+ // CLANG16: define {{.*}}@_ZN5test61fIiEEvT_(
+ template void f(int);
+
+ template<typename T>
+ void g(D<T> auto) {}
+ // CHECK: define {{.*}}@_ZN5test61gIiTk1DIT_EiEEvT0_(
+ // CLANG16: define {{.*}}@_ZN5test61gIiiEEvT0_(
+ template void g<int>(int);
+}
+
+namespace test7 {
+ // Constrained lambdas.
+ template<typename T> void f() {
+ // Ensure that requires-clauses affect lambda numbering.
+ // CHECK-LABEL: define {{.*}}@_ZN5test71fIiEEvv(
+ // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E_clIiiEEDaS3_Q1CIDtfp_EE(
+ ([]<typename U> requires C<T> && C<U> (auto x) requires C<decltype(x)> {}).template operator()<int>(0);
+ // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E0_clIiiEEDaS3_Qaa1CIDtfp_EELb1E(
+ ([]<typename U> requires C<T> && C<U> (auto x) requires C<decltype(x)> && true {}).template operator()<int>(0);
+ // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E1_clIiiEEDaS3_Q1CIDtfp_EE(
+ ([]<typename U> requires C<T> && C<U> (auto x) requires C<decltype(x)> {}).template operator()<int>(0);
+ // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyT0_E_clIiiEEDaS1_(
+ ([]<typename U> (auto x){}).template operator()<int>(0);
+ }
+ template void f<int>();
+}
diff --git a/clang/test/CodeGenCXX/mangle-exprs.cpp b/clang/test/CodeGenCXX/mangle-exprs.cpp
index e7008eee4643d94..88406d7fe6d80b5 100644
--- a/clang/test/CodeGenCXX/mangle-exprs.cpp
+++ b/clang/test/CodeGenCXX/mangle-exprs.cpp
@@ -93,9 +93,9 @@ namespace Casts {
template void static_<4>(void*);
// CHECK-LABEL: define weak_odr void @_ZN5Casts12reinterpret_ILj4EiEEvPN9enable_ifIXleT_szrcPT0_Li0EEvE4typeE
template void reinterpret_<4, int>(void*);
- // CHECK-LABEL: define weak_odr void @_ZN5Casts6const_IiXadL_ZNS_1iEEEEEvPN9enable_ifIXleLi0EszccPT_T0_EvE4typeE
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts6const_IiTnPT_XadL_ZNS_1iEEEEEvPN9enable_ifIXleLi0EszccS2_T0_EvE4typeE
template void const_<int, &i>(void*);
- // CHECK-LABEL: define weak_odr void @_ZN5Casts8dynamic_INS_1SEXadL_ZNS_1sEEEEEvPN9enable_ifIXleLi0EszdcPT_T0_EvE4typeE
+ // CHECK-LABEL: define weak_odr void @_ZN5Casts8dynamic_INS_1SETnPT_XadL_ZNS_1sEEEEEvPN9enable_ifIXleLi0EszdcS3_T0_EvE4typeE
template void dynamic_<struct S, &s>(void*);
// CHECK-LABEL: define weak_odr void @_ZN5Casts1fILi6EEENS_1TIXT_EEEv
diff --git a/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp b/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp
index 7577ef8f2561f0d..78fa7c378c88d50 100644
--- a/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp
+++ b/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp
@@ -74,40 +74,40 @@ template<auto tparam> void dummy(){}
void uses() {
// Zero init'ed cases.
dummy<wrapper1<int>{}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper1IiEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper1IiEEEEvv
// DEMANGLED: call void @void dummy<wrapper1<int>{}>()()
dummy<wrapper2<float>{}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper2IfEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper2IfEEEEvv
// DEMANGLED: call void @void dummy<wrapper2<float>{}>()()
dummy<wrapper3<short>{}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper3IsEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper3IsEEEEvv
// DEMANGLED: call void @void dummy<wrapper3<short>{}>()()
dummy<wrapper4<double>{}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper4IdEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper4IdEEEEvv
// DEMANGLED: call void @void dummy<wrapper4<double>{}>()()
dummy<wrapper5<long long>{}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper5IxEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper5IxEEEEvv
// DEMANGLED: call void @void dummy<wrapper5<long long>{}>()()
dummy<wrapper6<int>{}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper6IiEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper6IiEEEEvv
// DEMANGLED: call void @void dummy<wrapper6<int>{}>()()
dummy<wrapper1<double>{123.0}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper1IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper1IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv
// DEMANGLED: call void @void dummy<wrapper1<double>{wrapper1<double>::'unnamed'{.RightName = wrapper1<double>::'unnamed'::'unnamed'{0x1.ec{{.*}}p+6}}}>()()
dummy<wrapper2<double>{123.0}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper2IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper2IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv
// DEMANGLED: call void @void dummy<wrapper2<double>{wrapper2<double>::'unnamed'{.RightName = wrapper2<double>::'unnamed'::'unnamed'{0x1.ec{{.*}}p+6}}}>()()
dummy<wrapper3<double>{123, 456}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper3IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Etl4BaseLi123EELd407c800000000000EEEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper3IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Etl4BaseLi123EELd407c800000000000EEEEEEvv
// DEMANGLED: call void @void dummy<wrapper3<double>{wrapper3<double>::'unnamed'{.RightName = wrapper3<double>::'unnamed'::'unnamed'{Base{123}, 0x1.c8{{.*}}p+8}}}>()()
dummy<wrapper4<double>{123}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper4IdEtlNS1_Ut_Edi9RightNameLi123EEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper4IdEtlNS1_Ut_Edi9RightNameLi123EEEEEvv
// DEMANGLED: call void @void dummy<wrapper4<double>{wrapper4<double>::'unnamed'{.RightName = 123}}>()()
dummy<wrapper5<double>{123.0, 456.0}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper5IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_EtlNS3_Ut_ELd405ec00000000000EELd407c800000000000EEEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper5IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_EtlNS3_Ut_ELd405ec00000000000EELd407c800000000000EEEEEEvv
// DEMANGLED: call void @void dummy<wrapper5<double>{wrapper5<double>::'unnamed'{.RightName = wrapper5<double>::'unnamed'::'unnamed'{wrapper5<double>::'unnamed'::'unnamed'::'unnamed'{0x1.ec{{.*}}p+6}, 0x1.c8{{.*}}p+8}}}>()()
dummy<wrapper6<double>{1}>();
- // CHECK: call void @_Z5dummyIXtl8wrapper6IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd3ff0000000000000EEEEEEvv
+ // CHECK: call void @_Z5dummyITnDaXtl8wrapper6IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd3ff0000000000000EEEEEEvv
// DEMANGELD: call void @void dummy<wrapper6<double>{wrapper6<double>::'unnamed'{.RightName = wrapper6<double>::'unnamed'::'unnamed'{.RightName = 0x1{{.*}}p+0}}}>()()
}
diff --git a/clang/test/CodeGenCXX/mangle-requires.cpp b/clang/test/CodeGenCXX/mangle-requires.cpp
new file mode 100644
index 000000000000000..9897b440a664478
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-requires.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -verify -std=c++2a -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s
+// expected-no-diagnostics
+
+template <typename T, int N> concept SmallerThan = sizeof(T) < N;
+template <typename T> concept Small = SmallerThan<T, 1000>;
+
+template <typename T> struct X { using type = T; };
+
+template <typename T> void f(int n) requires requires {
+ // simple-requirement
+ T();
+ n;
+ n == T();
+ // compound-requirement
+ {T() + 1} -> Small;
+ {T() - 1} noexcept;
+ {T() * 2} noexcept -> SmallerThan<1234>;
+ // type-requirement
+ typename T;
+ typename X<T>;
+ typename X<T>::type;
+ typename X<decltype(n)>;
+ // nested-requirement
+ requires SmallerThan<T, 256>;
+} {}
+// CHECK: define {{.*}}@_Z1fIiEviQrqXcvT__EXfp_Xeqfp_cvS0__EXplcvS0__ELi1ER5SmallXmicvS0__ELi1ENXmlcvS0__ELi2ENR11SmallerThanILi1234EETS0_T1XIS0_ETNS3_4typeETS2_IiEQ11SmallerThanIS0_Li256EEE(
+template void f<int>(int);
+
+template <typename T> void g(int n) requires requires (T m) {
+ // reference to our parameter vs an enclosing parameter
+ n + m;
+} {}
+// CHECK: define {{.*}}@_Z1gIiEviQrQT__XplfL0p_fp_E(
+template void g<int>(int);
diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp
index 7611bae5dbd6995..52aefa8dfc2b97e 100644
--- a/clang/test/CodeGenCXX/mangle-template.cpp
+++ b/clang/test/CodeGenCXX/mangle-template.cpp
@@ -158,13 +158,13 @@ namespace test12 {
const int n = 10;
template<typename T, T v> void test() {}
void use() {
- // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv(
+ // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIFivETnT_XadL_ZNS_L1fEvEEEEvv(
test<int(), &f>();
- // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRFivEL_ZNS_L1fEvEEEvv(
+ // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRFivETnT_L_ZNS_L1fEvEEEvv(
test<int(&)(), f>();
- // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv(
+ // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIPKiTnT_XadL_ZNS_L1nEEEEEvv(
test<const int*, &n>();
- // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRKiL_ZNS_L1nEEEEvv(
+ // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRKiTnT_L_ZNS_L1nEEEEvv(
test<const int&, n>();
}
}
diff --git a/clang/test/CodeGenCXX/matrix-type.cpp b/clang/test/CodeGenCXX/matrix-type.cpp
index 21255f67c61c589..4d94c281ae8c45c 100644
--- a/clang/test/CodeGenCXX/matrix-type.cpp
+++ b/clang/test/CodeGenCXX/matrix-type.cpp
@@ -261,10 +261,10 @@ void test_auto_t() {
// CHECK-LABEL: define{{.*}} void @_Z11test_auto_tv()
// CHECK-NEXT: entry:
// CHECK-NEXT: %m = alloca [130 x i32], align 4
- // CHECK-NEXT: call void @_Z3fooILm13EEvRu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(520) %m)
+ // CHECK-NEXT: call void @_Z3fooITnDaLm13EEvRu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(520) %m)
// CHECK-NEXT: ret void
- // CHECK-LABEL: define linkonce_odr void @_Z3fooILm13EEvRu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(520) %m)
+ // CHECK-LABEL: define linkonce_odr void @_Z3fooITnDaLm13EEvRu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(520) %m)
// CHECK-NEXT: entry:
// CHECK-NEXT: %m.addr = alloca ptr, align 8
// CHECK-NEXT: store ptr %m, ptr %m.addr, align 8
diff --git a/clang/test/OpenMP/tile_codegen.cpp b/clang/test/OpenMP/tile_codegen.cpp
index 56ebc78637bc530..2926d557a903867 100644
--- a/clang/test/OpenMP/tile_codegen.cpp
+++ b/clang/test/OpenMP/tile_codegen.cpp
@@ -983,11 +983,11 @@ extern "C" void tfoo7() {
// CHECK1-LABEL: define {{[^@]+}}@tfoo7
// CHECK1-SAME: () #[[ATTR0]] {
// CHECK1-NEXT: entry:
-// CHECK1-NEXT: call void @_Z4foo7IiLi3ELi5EEvT_S0_(i32 noundef 0, i32 noundef 42)
+// CHECK1-NEXT: call void @_Z4foo7IiTnT_Li3ETnS0_Li5EEvS0_S0_(i32 noundef 0, i32 noundef 42)
// CHECK1-NEXT: ret void
//
//
-// CHECK1-LABEL: define {{[^@]+}}@_Z4foo7IiLi3ELi5EEvT_S0_
+// CHECK1-LABEL: define {{[^@]+}}@_Z4foo7IiTnT_Li3ETnS0_Li5EEvS0_S0_
// CHECK1-SAME: (i32 noundef [[START:%.*]], i32 noundef [[END:%.*]]) #[[ATTR0]] comdat {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[START_ADDR:%.*]] = alloca i32, align 4
@@ -1977,11 +1977,11 @@ extern "C" void tfoo7() {
// CHECK2-LABEL: define {{[^@]+}}@tfoo7
// CHECK2-SAME: () #[[ATTR2]] {
// CHECK2-NEXT: entry:
-// CHECK2-NEXT: call void @_Z4foo7IiLi3ELi5EEvT_S0_(i32 noundef 0, i32 noundef 42)
+// CHECK2-NEXT: call void @_Z4foo7IiTnT_Li3ETnS0_Li5EEvS0_S0_(i32 noundef 0, i32 noundef 42)
// CHECK2-NEXT: ret void
//
//
-// CHECK2-LABEL: define {{[^@]+}}@_Z4foo7IiLi3ELi5EEvT_S0_
+// CHECK2-LABEL: define {{[^@]+}}@_Z4foo7IiTnT_Li3ETnS0_Li5EEvS0_S0_
// CHECK2-SAME: (i32 noundef [[START:%.*]], i32 noundef [[END:%.*]]) #[[ATTR2]] comdat {
// CHECK2-NEXT: entry:
// CHECK2-NEXT: [[START_ADDR:%.*]] = alloca i32, align 4
diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index e96fee18b27a3ad..6fdfe38bd0f1f87 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -133,8 +133,8 @@ template <class T, size_t N> class PODSmallVector {
--Last;
}
- void dropBack(size_t Index) {
- assert(Index <= size() && "dropBack() can't expand!");
+ void shrinkToSize(size_t Index) {
+ assert(Index <= size() && "shrinkToSize() can't expand!");
Last = First + Index;
}
@@ -878,21 +878,22 @@ class FunctionEncoding final : public Node {
const Node *Name;
NodeArray Params;
const Node *Attrs;
+ const Node *Requires;
Qualifiers CVQuals;
FunctionRefQual RefQual;
public:
FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,
- const Node *Attrs_, Qualifiers CVQuals_,
- FunctionRefQual RefQual_)
+ const Node *Attrs_, const Node *Requires_,
+ Qualifiers CVQuals_, FunctionRefQual RefQual_)
: Node(KFunctionEncoding,
/*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
/*FunctionCache=*/Cache::Yes),
Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
- CVQuals(CVQuals_), RefQual(RefQual_) {}
+ Requires(Requires_), CVQuals(CVQuals_), RefQual(RefQual_) {}
template<typename Fn> void match(Fn F) const {
- F(Ret, Name, Params, Attrs, CVQuals, RefQual);
+ F(Ret, Name, Params, Attrs, Requires, CVQuals, RefQual);
}
Qualifiers getCVQuals() const { return CVQuals; }
@@ -935,6 +936,11 @@ class FunctionEncoding final : public Node {
if (Attrs != nullptr)
Attrs->print(OB);
+
+ if (Requires != nullptr) {
+ OB += " requires ";
+ Requires->print(OB);
+ }
}
};
@@ -1006,6 +1012,24 @@ struct NestedName : Node {
}
};
+struct MemberLikeFriendName : Node {
+ Node *Qual;
+ Node *Name;
+
+ MemberLikeFriendName(Node *Qual_, Node *Name_)
+ : Node(KMemberLikeFriendName), Qual(Qual_), Name(Name_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Qual, Name); }
+
+ std::string_view getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Qual->print(OB);
+ OB += "::friend ";
+ Name->print(OB);
+ }
+};
+
struct ModuleName : Node {
ModuleName *Parent;
Node *Name;
@@ -1171,6 +1195,24 @@ class SyntheticTemplateParamName final : public Node {
}
};
+class TemplateParamQualifiedArg final : public Node {
+ Node *Param;
+ Node *Arg;
+
+public:
+ TemplateParamQualifiedArg(Node *Param_, Node *Arg_)
+ : Node(KTemplateParamQualifiedArg), Param(Param_), Arg(Arg_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Param, Arg); }
+
+ Node *getArg() { return Arg; }
+
+ void printLeft(OutputBuffer &OB) const override {
+ // Don't print Param to keep the output consistent.
+ Arg->print(OB);
+ }
+};
+
/// A template type parameter declaration, 'typename T'.
class TypeTemplateParamDecl final : public Node {
Node *Name;
@@ -1186,6 +1228,26 @@ class TypeTemplateParamDecl final : public Node {
void printRight(OutputBuffer &OB) const override { Name->print(OB); }
};
+/// A constrained template type parameter declaration, 'C<U> T'.
+class ConstrainedTypeTemplateParamDecl final : public Node {
+ Node *Constraint;
+ Node *Name;
+
+public:
+ ConstrainedTypeTemplateParamDecl(Node *Constraint_, Node *Name_)
+ : Node(KConstrainedTypeTemplateParamDecl, Cache::Yes),
+ Constraint(Constraint_), Name(Name_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Constraint, Name); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Constraint->print(OB);
+ OB += " ";
+ }
+
+ void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+};
+
/// A non-type template parameter declaration, 'int N'.
class NonTypeTemplateParamDecl final : public Node {
Node *Name;
@@ -1214,13 +1276,14 @@ class NonTypeTemplateParamDecl final : public Node {
class TemplateTemplateParamDecl final : public Node {
Node *Name;
NodeArray Params;
+ Node *Requires;
public:
- TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)
+ TemplateTemplateParamDecl(Node *Name_, NodeArray Params_, Node *Requires_)
: Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),
- Params(Params_) {}
+ Params(Params_), Requires(Requires_) {}
- template<typename Fn> void match(Fn F) const { F(Name, Params); }
+ template <typename Fn> void match(Fn F) const { F(Name, Params, Requires); }
void printLeft(OutputBuffer &OB) const override {
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
@@ -1229,7 +1292,13 @@ class TemplateTemplateParamDecl final : public Node {
OB += "> typename ";
}
- void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+ void printRight(OutputBuffer &OB) const override {
+ Name->print(OB);
+ if (Requires != nullptr) {
+ OB += " requires ";
+ Requires->print(OB);
+ }
+ }
};
/// A template parameter pack declaration, 'typename ...T'.
@@ -1326,7 +1395,7 @@ class ParameterPack final : public Node {
/// A variadic template argument. This node represents an occurrence of
/// J<something>E in some <template-args>. It isn't itself unexpanded, unless
-/// one of it's Elements is. The parser inserts a ParameterPack into the
+/// one of its Elements is. The parser inserts a ParameterPack into the
/// TemplateParams table if the <template-args> this pack belongs to apply to an
/// <encoding>.
class TemplateArgumentPack final : public Node {
@@ -1392,11 +1461,13 @@ class ParameterPackExpansion final : public Node {
class TemplateArgs final : public Node {
NodeArray Params;
+ Node *Requires;
public:
- TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
+ TemplateArgs(NodeArray Params_, Node *Requires_)
+ : Node(KTemplateArgs), Params(Params_), Requires(Requires_) {}
- template<typename Fn> void match(Fn F) const { F(Params); }
+ template<typename Fn> void match(Fn F) const { F(Params, Requires); }
NodeArray getParams() { return Params; }
@@ -1405,6 +1476,7 @@ class TemplateArgs final : public Node {
OB += "<";
Params.printWithComma(OB);
OB += ">";
+ // Don't print the requires clause to keep the output simple.
}
};
@@ -1655,17 +1727,21 @@ class UnnamedTypeName : public Node {
class ClosureTypeName : public Node {
NodeArray TemplateParams;
+ const Node *Requires1;
NodeArray Params;
+ const Node *Requires2;
std::string_view Count;
public:
- ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
+ ClosureTypeName(NodeArray TemplateParams_, const Node *Requires1_,
+ NodeArray Params_, const Node *Requires2_,
std::string_view Count_)
: Node(KClosureTypeName), TemplateParams(TemplateParams_),
- Params(Params_), Count(Count_) {}
+ Requires1(Requires1_), Params(Params_), Requires2(Requires2_),
+ Count(Count_) {}
template<typename Fn> void match(Fn F) const {
- F(TemplateParams, Params, Count);
+ F(TemplateParams, Requires1, Params, Requires2, Count);
}
void printDeclarator(OutputBuffer &OB) const {
@@ -1675,12 +1751,22 @@ class ClosureTypeName : public Node {
TemplateParams.printWithComma(OB);
OB += ">";
}
+ if (Requires1 != nullptr) {
+ OB += " requires ";
+ Requires1->print(OB);
+ OB += " ";
+ }
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
+ if (Requires2 != nullptr) {
+ OB += " requires ";
+ Requires2->print(OB);
+ }
}
void printLeft(OutputBuffer &OB) const override {
+ // FIXME: This demangling is not particularly readable.
OB += "\'lambda";
OB += Count;
OB += "\'";
@@ -2309,6 +2395,95 @@ class IntegerLiteral : public Node {
}
};
+class RequiresExpr : public Node {
+ NodeArray Parameters;
+ NodeArray Requirements;
+public:
+ RequiresExpr(NodeArray Parameters_, NodeArray Requirements_)
+ : Node(KRequiresExpr), Parameters(Parameters_),
+ Requirements(Requirements_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Parameters, Requirements); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "requires";
+ if (!Parameters.empty()) {
+ OB += ' ';
+ OB.printOpen();
+ Parameters.printWithComma(OB);
+ OB.printClose();
+ }
+ OB += ' ';
+ OB.printOpen('{');
+ for (const Node *Req : Requirements) {
+ Req->print(OB);
+ }
+ OB += ' ';
+ OB.printClose('}');
+ }
+};
+
+class ExprRequirement : public Node {
+ const Node *Expr;
+ bool IsNoexcept;
+ const Node *TypeConstraint;
+public:
+ ExprRequirement(const Node *Expr_, bool IsNoexcept_,
+ const Node *TypeConstraint_)
+ : Node(KExprRequirement), Expr(Expr_), IsNoexcept(IsNoexcept_),
+ TypeConstraint(TypeConstraint_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Expr, IsNoexcept, TypeConstraint);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += " ";
+ if (IsNoexcept || TypeConstraint)
+ OB.printOpen('{');
+ Expr->print(OB);
+ if (IsNoexcept || TypeConstraint)
+ OB.printClose('}');
+ if (IsNoexcept)
+ OB += " noexcept";
+ if (TypeConstraint) {
+ OB += " -> ";
+ TypeConstraint->print(OB);
+ }
+ OB += ';';
+ }
+};
+
+class TypeRequirement : public Node {
+ const Node *Type;
+public:
+ TypeRequirement(const Node *Type_)
+ : Node(KTypeRequirement), Type(Type_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Type); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += " typename ";
+ Type->print(OB);
+ OB += ';';
+ }
+};
+
+class NestedRequirement : public Node {
+ const Node *Constraint;
+public:
+ NestedRequirement(const Node *Constraint_)
+ : Node(KNestedRequirement), Constraint(Constraint_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Constraint); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += " requires ";
+ Constraint->print(OB);
+ OB += ';';
+ }
+};
+
template <class Float> struct FloatData;
namespace float_literal_impl {
@@ -2403,6 +2578,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
// table.
PODSmallVector<Node *, 32> Subs;
+ // A list of template argument values corresponding to a template parameter
+ // list.
using TemplateParamList = PODSmallVector<Node *, 8>;
class ScopedTemplateParamList {
@@ -2418,8 +2595,9 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
}
~ScopedTemplateParamList() {
assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);
- Parser->TemplateParams.dropBack(OldNumTemplateParamLists);
+ Parser->TemplateParams.shrinkToSize(OldNumTemplateParamLists);
}
+ TemplateParamList *params() { return &Params; }
};
// Template parameter table. Like the above, but referenced like "T42_".
@@ -2434,12 +2612,31 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
// parameter list, the corresponding parameter list pointer will be null.
PODSmallVector<TemplateParamList *, 4> TemplateParams;
+ class SaveTemplateParams {
+ AbstractManglingParser *Parser;
+ decltype(TemplateParams) OldParams;
+ decltype(OuterTemplateParams) OldOuterParams;
+
+ public:
+ SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
+ OldParams = std::move(Parser->TemplateParams);
+ OldOuterParams = std::move(Parser->OuterTemplateParams);
+ Parser->TemplateParams.clear();
+ Parser->OuterTemplateParams.clear();
+ }
+ ~SaveTemplateParams() {
+ Parser->TemplateParams = std::move(OldParams);
+ Parser->OuterTemplateParams = std::move(OldOuterParams);
+ }
+ };
+
// Set of unresolved forward <template-param> references. These can occur in a
// conversion operator's type, and are resolved in the enclosing <encoding>.
PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;
bool TryToParseTemplateArgs = true;
bool PermitForwardTemplateReferences = false;
+ bool InConstraintExpr = false;
size_t ParsingLambdaParamsAtLevel = (size_t)-1;
unsigned NumSyntheticTemplateParameters[3] = {};
@@ -2481,7 +2678,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
assert(FromPosition <= Names.size());
NodeArray res =
makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
- Names.dropBack(FromPosition);
+ Names.shrinkToSize(FromPosition);
return res;
}
@@ -2519,11 +2716,16 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
bool parseSeqId(size_t *Out);
Node *parseSubstitution();
Node *parseTemplateParam();
- Node *parseTemplateParamDecl();
+ Node *parseTemplateParamDecl(TemplateParamList *Params);
Node *parseTemplateArgs(bool TagTemplates = false);
Node *parseTemplateArg();
- /// Parse the <expr> production.
+ bool isTemplateParamDecl() {
+ return look() == 'T' &&
+ std::string_view("yptnk").find(look(1)) != std::string_view::npos;
+ }
+
+ /// Parse the <expression> production.
Node *parseExpr();
Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec);
Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec);
@@ -2536,6 +2738,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseFoldExpr();
Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
Node *parseSubobjectExpr();
+ Node *parseConstraintExpr();
+ Node *parseRequiresExpr();
/// Parse the <type> production.
Node *parseType();
@@ -2574,7 +2778,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
return true;
ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];
}
- ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
+ ForwardTemplateRefs.shrinkToSize(State.ForwardTemplateRefsBegin);
return false;
}
@@ -2727,6 +2931,10 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
return make<LocalName>(Encoding, StringLitName);
}
+ // The template parameters of the inner name are unrelated to those of the
+ // enclosing context.
+ SaveTemplateParams SaveTemplateParamsScope(this);
+
if (consumeIf('d')) {
parseNumber(true);
if (!consumeIf('_'))
@@ -2782,9 +2990,9 @@ AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
return Res;
}
-// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
+// <unqualified-name> ::= [<module-name>] F? L? <operator-name> [<abi-tags>]
// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
-// ::= [<module-name>] L? <source-name> [<abi-tags>]
+// ::= [<module-name>] F? L? <source-name> [<abi-tags>]
// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
// # structured binding declaration
// ::= [<module-name>] L? DC <source-name>+ E
@@ -2794,6 +3002,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
if (getDerived().parseModuleNameOpt(Module))
return nullptr;
+ bool IsMemberLikeFriend = Scope && consumeIf('F');
+
consumeIf('L');
Node *Result;
@@ -2824,7 +3034,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
Result = make<ModuleEntity>(Module, Result);
if (Result != nullptr)
Result = getDerived().parseAbiTags(Result);
- if (Result != nullptr && Scope != nullptr)
+ if (Result != nullptr && IsMemberLikeFriend)
+ Result = make<MemberLikeFriendName>(Scope, Result);
+ else if (Result != nullptr && Scope != nullptr)
Result = make<NestedName>(Scope, Result);
return Result;
@@ -2856,7 +3068,8 @@ bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
//
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
//
-// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+// <lambda-sig> ::= <template-param-decl>* [Q <requires-clause expression>]
+// <parameter type>+ # or "v" if the lambda has no parameters
template <typename Derived, typename Alloc>
Node *
AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
@@ -2877,10 +3090,10 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
ScopedTemplateParamList LambdaTemplateParams(this);
size_t ParamsBegin = Names.size();
- while (look() == 'T' &&
- std::string_view("yptn").find(look(1)) != std::string_view::npos) {
- Node *T = parseTemplateParamDecl();
- if (!T)
+ while (getDerived().isTemplateParamDecl()) {
+ Node *T =
+ getDerived().parseTemplateParamDecl(LambdaTemplateParams.params());
+ if (T == nullptr)
return nullptr;
Names.push_back(T);
}
@@ -2911,20 +3124,38 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
if (TempParams.empty())
TemplateParams.pop_back();
- if (!consumeIf("vE")) {
+ Node *Requires1 = nullptr;
+ if (consumeIf('Q')) {
+ Requires1 = getDerived().parseConstraintExpr();
+ if (Requires1 == nullptr)
+ return nullptr;
+ }
+
+ if (!consumeIf("v")) {
do {
Node *P = getDerived().parseType();
if (P == nullptr)
return nullptr;
Names.push_back(P);
- } while (!consumeIf('E'));
+ } while (look() != 'E' && look() != 'Q');
}
NodeArray Params = popTrailingNodeArray(ParamsBegin);
+ Node *Requires2 = nullptr;
+ if (consumeIf('Q')) {
+ Requires2 = getDerived().parseConstraintExpr();
+ if (Requires2 == nullptr)
+ return nullptr;
+ }
+
+ if (!consumeIf('E'))
+ return nullptr;
+
std::string_view Count = parseNumber();
if (!consumeIf('_'))
return nullptr;
- return make<ClosureTypeName>(TempParams, Params, Count);
+ return make<ClosureTypeName>(TempParams, Requires1, Params, Requires2,
+ Count);
}
if (consumeIf("Ub")) {
(void)parseNumber();
@@ -3961,6 +4192,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
case 'c':
First += 2;
return make<NameType>("decltype(auto)");
+ // ::= Dk <type-constraint> # constrained auto
+ // ::= DK <type-constraint> # constrained decltype(auto)
+ case 'k':
+ case 'K': {
+ std::string_view Kind = look(1) == 'k' ? " auto" : " decltype(auto)";
+ First += 2;
+ Node *Constraint = getDerived().parseName();
+ if (!Constraint)
+ return nullptr;
+ return make<PostfixQualifiedType>(Constraint, Kind);
+ }
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
case 'n':
First += 2;
@@ -4512,6 +4754,75 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
}
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseConstraintExpr() {
+ // Within this expression, all enclosing template parameter lists are in
+ // scope.
+ ScopedOverride<bool> SaveInConstraintExpr(InConstraintExpr, true);
+ return getDerived().parseExpr();
+}
+
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseRequiresExpr() {
+ NodeArray Params;
+ if (consumeIf("rQ")) {
+ // <expression> ::= rQ <bare-function-type> _ <requirement>+ E
+ size_t ParamsBegin = Names.size();
+ while (!consumeIf('_')) {
+ Node *Type = getDerived().parseType();
+ if (Type == nullptr)
+ return nullptr;
+ Names.push_back(Type);
+ }
+ Params = popTrailingNodeArray(ParamsBegin);
+ } else if (!consumeIf("rq")) {
+ // <expression> ::= rq <requirement>+ E
+ return nullptr;
+ }
+
+ size_t ReqsBegin = Names.size();
+ do {
+ Node *Constraint = nullptr;
+ if (consumeIf('X')) {
+ // <requirement> ::= X <expression> [N] [R <type-constraint>]
+ Node *Expr = getDerived().parseExpr();
+ if (Expr == nullptr)
+ return nullptr;
+ bool Noexcept = consumeIf('N');
+ Node *TypeReq = nullptr;
+ if (consumeIf('R')) {
+ TypeReq = getDerived().parseName();
+ if (TypeReq == nullptr)
+ return nullptr;
+ }
+ Constraint = make<ExprRequirement>(Expr, Noexcept, TypeReq);
+ } else if (consumeIf('T')) {
+ // <requirement> ::= T <type>
+ Node *Type = getDerived().parseType();
+ if (Type == nullptr)
+ return nullptr;
+ Constraint = make<TypeRequirement>(Type);
+ } else if (consumeIf('Q')) {
+ // <requirement> ::= Q <constraint-expression>
+ //
+ // FIXME: We use <expression> instead of <constraint-expression>. Either
+ // the requires expression is already inside a constraint expression, in
+ // which case it makes no
diff erence, or we're in a requires-expression
+ // that might be partially-substituted, where the language behavior is
+ // not yet settled and clang mangles after substitution.
+ Node *NestedReq = getDerived().parseExpr();
+ if (NestedReq == nullptr)
+ return nullptr;
+ Constraint = make<NestedRequirement>(NestedReq);
+ }
+ if (Constraint == nullptr)
+ return nullptr;
+ Names.push_back(Constraint);
+ } while (!consumeIf('E'));
+
+ return make<RequiresExpr>(Params, popTrailingNodeArray(ReqsBegin));
+}
+
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <ternary operator-name> <expression> <expression> <expression>
@@ -4748,6 +5059,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return Ex;
return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
}
+ if (look() == 'r' && (look(1) == 'q' || look(1) == 'Q'))
+ return parseRequiresExpr();
if (consumeIf("so"))
return parseSubobjectExpr();
if (consumeIf("sp")) {
@@ -5026,29 +5339,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
}
// <encoding> ::= <function name> <bare-function-type>
+// [`Q` <requires-clause expr>]
// ::= <data name>
// ::= <special-name>
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
// The template parameters of an encoding are unrelated to those of the
// enclosing context.
- class SaveTemplateParams {
- AbstractManglingParser *Parser;
- decltype(TemplateParams) OldParams;
- decltype(OuterTemplateParams) OldOuterParams;
-
- public:
- SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
- OldParams = std::move(Parser->TemplateParams);
- OldOuterParams = std::move(Parser->OuterTemplateParams);
- Parser->TemplateParams.clear();
- Parser->OuterTemplateParams.clear();
- }
- ~SaveTemplateParams() {
- Parser->TemplateParams = std::move(OldParams);
- Parser->OuterTemplateParams = std::move(OldOuterParams);
- }
- } SaveTemplateParams(this);
+ SaveTemplateParams SaveTemplateParamsScope(this);
if (look() == 'G' || look() == 'T')
return getDerived().parseSpecialName();
@@ -5092,22 +5390,27 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
return nullptr;
}
- if (consumeIf('v'))
- return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
- Attrs, NameInfo.CVQualifiers,
- NameInfo.ReferenceQualifier);
+ NodeArray Params;
+ if (!consumeIf('v')) {
+ size_t ParamsBegin = Names.size();
+ do {
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ Names.push_back(Ty);
+ } while (!IsEndOfEncoding() && look() != 'Q');
+ Params = popTrailingNodeArray(ParamsBegin);
+ }
- size_t ParamsBegin = Names.size();
- do {
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
+ Node *Requires = nullptr;
+ if (consumeIf('Q')) {
+ Requires = getDerived().parseConstraintExpr();
+ if (!Requires)
return nullptr;
- Names.push_back(Ty);
- } while (!IsEndOfEncoding());
+ }
- return make<FunctionEncoding>(ReturnType, Name,
- popTrailingNodeArray(ParamsBegin),
- Attrs, NameInfo.CVQualifiers,
+ return make<FunctionEncoding>(ReturnType, Name, Params, Attrs, Requires,
+ NameInfo.CVQualifiers,
NameInfo.ReferenceQualifier);
}
@@ -5269,6 +5572,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
// ::= TL <level-1> _ <parameter-2 non-negative number> _
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
+ const char *Begin = First;
if (!consumeIf('T'))
return nullptr;
@@ -5290,6 +5594,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
return nullptr;
}
+ // We don't track enclosing template parameter levels well enough to reliably
+ // substitute them all within a <constraint-expression>, so print the
+ // parameter numbering instead for now.
+ // TODO: Track all enclosing template parameters and substitute them here.
+ if (InConstraintExpr) {
+ return make<NameType>(std::string_view(Begin, First - 1 - Begin));
+ }
+
// If we're in a context where this <template-param> refers to a
// <template-arg> further ahead in the mangled name (currently just conversion
// operator types), then we should only look it up in the right context.
@@ -5327,11 +5639,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
// ::= Tt <template-param-decl>* E # template parameter
// ::= Tp <template-param-decl> # parameter pack
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl(
+ TemplateParamList *Params) {
auto InventTemplateParamName = [&](TemplateParamKind Kind) {
unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;
Node *N = make<SyntheticTemplateParamName>(Kind, Index);
- if (N) TemplateParams.back()->push_back(N);
+ if (N && Params)
+ Params->push_back(N);
return N;
};
@@ -5342,6 +5656,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
return make<TypeTemplateParamDecl>(Name);
}
+ if (consumeIf("Tk")) {
+ Node *Constraint = getDerived().parseName();
+ if (!Constraint)
+ return nullptr;
+ Node *Name = InventTemplateParamName(TemplateParamKind::Type);
+ if (!Name)
+ return nullptr;
+ return make<ConstrainedTypeTemplateParamDecl>(Constraint, Name);
+ }
+
if (consumeIf("Tn")) {
Node *Name = InventTemplateParamName(TemplateParamKind::NonType);
if (!Name)
@@ -5358,18 +5682,25 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
return nullptr;
size_t ParamsBegin = Names.size();
ScopedTemplateParamList TemplateTemplateParamParams(this);
- while (!consumeIf("E")) {
- Node *P = parseTemplateParamDecl();
+ Node *Requires = nullptr;
+ while (!consumeIf('E')) {
+ Node *P = parseTemplateParamDecl(TemplateTemplateParamParams.params());
if (!P)
return nullptr;
Names.push_back(P);
+ if (consumeIf('Q')) {
+ Requires = getDerived().parseConstraintExpr();
+ if (Requires == nullptr || !consumeIf('E'))
+ return nullptr;
+ break;
+ }
}
- NodeArray Params = popTrailingNodeArray(ParamsBegin);
- return make<TemplateTemplateParamDecl>(Name, Params);
+ NodeArray InnerParams = popTrailingNodeArray(ParamsBegin);
+ return make<TemplateTemplateParamDecl>(Name, InnerParams, Requires);
}
if (consumeIf("Tp")) {
- Node *P = parseTemplateParamDecl();
+ Node *P = parseTemplateParamDecl(Params);
if (!P)
return nullptr;
return make<TemplateParamPackDecl>(P);
@@ -5383,6 +5714,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
// ::= <expr-primary> # simple expressions
// ::= J <template-arg>* E # argument pack
// ::= LZ <encoding> E # extension
+// ::= <template-param-decl> <template-arg>
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
switch (look()) {
@@ -5417,6 +5749,18 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
// ::= <expr-primary> # simple expressions
return getDerived().parseExprPrimary();
}
+ case 'T': {
+ // Either <template-param> or a <template-param-decl> <template-arg>.
+ if (!getDerived().isTemplateParamDecl())
+ return getDerived().parseType();
+ Node *Param = getDerived().parseTemplateParamDecl(nullptr);
+ if (!Param)
+ return nullptr;
+ Node *Arg = getDerived().parseTemplateArg();
+ if (!Arg)
+ return nullptr;
+ return make<TemplateParamQualifiedArg>(Param, Arg);
+ }
default:
return getDerived().parseType();
}
@@ -5439,30 +5783,39 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
}
size_t ArgsBegin = Names.size();
+ Node *Requires = nullptr;
while (!consumeIf('E')) {
if (TagTemplates) {
- auto OldParams = std::move(TemplateParams);
Node *Arg = getDerived().parseTemplateArg();
- TemplateParams = std::move(OldParams);
if (Arg == nullptr)
return nullptr;
Names.push_back(Arg);
Node *TableEntry = Arg;
+ if (Arg->getKind() == Node::KTemplateParamQualifiedArg) {
+ TableEntry =
+ static_cast<TemplateParamQualifiedArg *>(TableEntry)->getArg();
+ }
if (Arg->getKind() == Node::KTemplateArgumentPack) {
TableEntry = make<ParameterPack>(
static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
if (!TableEntry)
return nullptr;
}
- TemplateParams.back()->push_back(TableEntry);
+ OuterTemplateParams.push_back(TableEntry);
} else {
Node *Arg = getDerived().parseTemplateArg();
if (Arg == nullptr)
return nullptr;
Names.push_back(Arg);
}
+ if (consumeIf('Q')) {
+ Requires = getDerived().parseConstraintExpr();
+ if (!Requires || !consumeIf('E'))
+ return nullptr;
+ break;
+ }
}
- return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
+ return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin), Requires);
}
// <mangled-name> ::= _Z <encoding>
diff --git a/libcxxabi/src/demangle/ItaniumNodes.def b/libcxxabi/src/demangle/ItaniumNodes.def
index f615cb9fadb05e8..74dc7097c1b30aa 100644
--- a/libcxxabi/src/demangle/ItaniumNodes.def
+++ b/libcxxabi/src/demangle/ItaniumNodes.def
@@ -36,6 +36,7 @@ NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
+NODE(MemberLikeFriendName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
@@ -44,7 +45,9 @@ NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
+NODE(TemplateParamQualifiedArg)
NODE(TypeTemplateParamDecl)
+NODE(ConstrainedTypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
@@ -91,5 +94,9 @@ NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
+NODE(RequiresExpr)
+NODE(ExprRequirement)
+NODE(TypeRequirement)
+NODE(NestedRequirement)
#undef NODE
diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp
index 471808db5d5b8fc..47cc29b2430e72b 100644
--- a/libcxxabi/test/test_demangle.pass.cpp
+++ b/libcxxabi/test/test_demangle.pass.cpp
@@ -29995,10 +29995,10 @@ const char* cases[][2] =
{"_Z15test_uuidofTypeI10TestStructEvDTu8__uuidofT_EE", "void test_uuidofType<TestStruct>(decltype(__uuidof(TestStruct)))"},
{"_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofXsrT_6memberEEE", "void test_uuidofExpr<HasMember>(decltype(__uuidof(HasMember::member)))"},
- // C++2a char8_t:
+ // C++20 char8_t:
{"_ZTSPDu", "typeinfo name for char8_t*"},
- // C++2a lambda-expressions:
+ // C++20 lambda-expressions:
{"_ZNK1xMUlTyT_E_clIiEEDaS_", "auto x::'lambda'<typename $T>($T)::operator()<int>(x) const"},
{"_ZNK1xMUlTnPA3_ivE_clILS0_0EEEDav", "auto x::'lambda'<int (*$N) [3]>()::operator()<(int [3])0>() const"},
{"_ZNK1xMUlTyTtTyTnT_TpTnPA3_TL0__ETpTyvE_clIi1XJfEEEDav", "auto x::'lambda'<typename $T, template<typename $T0, $T $N, $T0 (*...$N0) [3]> typename $TT, typename ...$T1>()::operator()<int, X, float>() const"},
@@ -30015,8 +30015,10 @@ const char* cases[][2] =
// See https://github.com/itanium-cxx-abi/cxx-abi/issues/106.
{"_ZN1XIZ1fIiEvOT_EUlS2_DpT0_E_EclIJEEEvDpT_", "void X<void f<int>(int&&)::'lambda'(int&&, auto...)>::operator()<>()"},
{"_ZZZZN6abcdef9abcdefghi29abcdefabcdefabcdefabcefabcdef27xxxxxxxxxxxxxxxxxxxxxxxxxxxEN4absl8DurationERKNSt3__u12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPNS1_19yyyyyyyyyyyyyyyyyyyEENK3$_5clEvENKUlvE_clEvE6zzzzzz", "abcdef::abcdefghi::abcdefabcdefabcdefabcefabcdef::xxxxxxxxxxxxxxxxxxxxxxxxxxx(absl::Duration, std::__u::basic_string<char, std::__u::char_traits<char>, std::__u::allocator<char>> const&, abcdef::abcdefghi::abcdefabcdefabcdefabcefabcdef::yyyyyyyyyyyyyyyyyyy*)::$_5::operator()() const::'lambda'()::operator()() const::zzzzzz"},
+ // See https://github.com/itanium-cxx-abi/cxx-abi/issues/165.
+ {"_ZN1C1fIiEEvDTtlNS_UlT_TL0__E_EEE", "void C::f<int>(decltype(C::'lambda'(int, auto){}))"},
- // C++2a class type non-type template parameters:
+ // C++20 class type non-type template parameters:
{"_Z1fIXtl1BLPi0ELi1EEEEvv", "void f<B{(int*)0, 1}>()"},
{"_Z1fIXtl1BLPi32EEEEvv", "void f<B{(int*)32}>()"},
{"_Z1fIXtl1BrcPiLi0EEEEvv", "void f<B{reinterpret_cast<int*>(0)}>()"},
@@ -30089,6 +30091,51 @@ const char* cases[][2] =
{"_ZW1ML4Oink", "Oink at M"},
{"_ZW1ML1fi", "f at M(int)"},
+ // C++20 concepts, see https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ {"_Z2f0IiE1SIX1CIT_EEEv", "S<C<int>> f0<int>()"},
+ {"_ZN5test21AIiEF1fEzQ4TrueIT_E", "test2::A<int>::friend f(...) requires True<T>"},
+ {"_ZN5test2F1gIvEEvzQaa4TrueIT_E4TrueITL0__E", "void test2::friend g<void>(...) requires True<T> && True<TL0_>"},
+ {"_ZN5test21hIvEEvzQ4TrueITL0__E", "void test2::h<void>(...) requires True<TL0_>"},
+ {"_ZN5test2F1iIvQaa4TrueIT_E4TrueITL0__EEEvz", "void test2::friend i<void>(...)"},
+ {"_ZN5test21jIvQ4TrueITL0__EEEvz", "void test2::j<void>(...)"},
+ {"_ZN5test2F1kITk4TruevQ4TrueIT_EEEvz", "void test2::friend k<void>(...)"},
+ {"_ZN5test21lITk4TruevEEvz", "void test2::l<void>(...)"},
+ {"_ZN5test31dITnDaLi0EEEvv", "void test3::d<0>()"},
+ {"_ZN5test31eITnDcLi0EEEvv", "void test3::e<0>()"},
+ {"_ZN5test31fITnDk1CLi0EEEvv", "void test3::f<0>()"},
+ {"_ZN5test31gITnDk1DIiELi0EEEvv", "void test3::g<0>()"},
+ {"_ZN5test31hIiTnDk1DIT_ELi0EEEvv", "void test3::h<int, 0>()"},
+ {"_ZN5test31iIiEEvDTnw_Dk1CpicvT__EEE", "void test3::i<int>(decltype(new C auto((int)())))"},
+ {"_ZN5test31jIiEEvDTnw_DK1CpicvT__EEE", "void test3::j<int>(decltype(new C decltype(auto)((int)())))"},
+ {"_ZN5test41fITk1CiEEvv", "void test4::f<int>()"},
+ {"_ZN5test41gITk1DIiEiEEvv", "void test4::g<int>()"},
+ {"_ZN5test51fINS_1XEEEvv", "void test5::f<test5::X>()"},
+ {"_ZN5test51fITtTyTnTL0__ENS_1YEEEvv", "void test5::f<test5::Y>()"},
+ {"_ZN5test51fITtTyTnTL0__ENS_1ZEEEvv", "void test5::f<test5::Z>()"},
+ {"_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1XEEEvv", "void test5::g<test5::X>()"},
+ {"_ZN5test51gINS_1YEEEvv", "void test5::g<test5::Y>()"},
+ {"_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1ZEEEvv", "void test5::g<test5::Z>()"},
+ {"_ZN5test51hITtTk1CTnTL0__ENS_1XEEEvv", "void test5::h<test5::X>()"},
+ {"_ZN5test51hITtTk1CTnTL0__ENS_1YEEEvv", "void test5::h<test5::Y>()"},
+ {"_ZN5test51hINS_1ZEEEvv", "void test5::h<test5::Z>()"},
+ {"_ZN5test51iITpTtTk1CTnTL0__EJNS_1XENS_1YENS_1ZEEEEvv", "void test5::i<test5::X, test5::Y, test5::Z>()"},
+ {"_ZN5test51iITpTtTk1CTnTL0__EJNS_1YENS_1ZENS_1XEEEEvv", "void test5::i<test5::Y, test5::Z, test5::X>()"},
+ {"_ZN5test51iIJNS_1ZENS_1XENS_1YEEEEvv", "void test5::i<test5::Z, test5::X, test5::Y>()"},
+ {"_ZN5test51pINS_1AEEEvv", "void test5::p<test5::A>()"},
+ {"_ZN5test51pITtTpTyENS_1BEEEvv", "void test5::p<test5::B>()"},
+ {"_ZN5test51qITtTyTyENS_1AEEEvv", "void test5::q<test5::A>()"},
+ {"_ZN5test51qINS_1BEEEvv", "void test5::q<test5::B>()"},
+ {"_ZN5test61fITk1CiEEvT_", "void test6::f<int>(int)"},
+ {"_ZN5test61gIiTk1DIT_EiEEvT0_", "void test6::g<int, int>(int)"},
+ {"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E_clIiiEEDaS3_Q1CIDtfp_EE", "auto void test7::f<int>()::'lambda'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(auto) const requires C<decltype(fp)>"},
+ {"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E0_clIiiEEDaS3_Qaa1CIDtfp_EELb1E", "auto void test7::f<int>()::'lambda0'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(auto) const requires C<decltype(fp)> && true"},
+ {"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E1_clIiiEEDaS3_Q1CIDtfp_EE", "auto void test7::f<int>()::'lambda1'<typename $T> requires C<T> && C<TL0_> (auto)::operator()<int, int>(auto) const requires C<decltype(fp)>"},
+ {"_ZZN5test71fIiEEvvENKUlTyT0_E_clIiiEEDaS1_", "auto void test7::f<int>()::'lambda'<typename $T>(auto)::operator()<int, int>(auto) const"},
+
+ // C++20 requires expressions, see https://github.com/itanium-cxx-abi/cxx-abi/issues/24.
+ {"_Z1fIiEviQrqXcvT__EXfp_Xeqfp_cvS0__EXplcvS0__ELi1ER5SmallXmicvS0__ELi1ENXmlcvS0__ELi2ENR11SmallerThanILi1234EETS0_T1XIS0_ETNS3_4typeETS2_IiEQ11SmallerThanIS0_Li256EEE", "void f<int>(int) requires requires { (T)(); fp; fp == (T)(); {(T)() + 1} -> Small; {(T)() - 1} noexcept; {(T)() * 2} noexcept -> SmallerThan<1234>; typename T; typename X<T>; typename X<T>::type; typename X<int>; requires SmallerThan<T, 256>; }"},
+ {"_Z1gIiEviQrQT__XplfL0p_fp_E", "void g<int>(int) requires requires (T) { fp + fp; }"},
+
// Special Substs a, b, d, i, o, s (not including std::)
{"_Z1fSaIiE", "f(std::allocator<int>)"},
{"_Z1fSbIiE", "f(std::basic_string<int>)"},
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 04faeb462e097e7..fde2085e2608941 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -19,6 +19,7 @@
#include "DemangleConfig.h"
#include "StringViewExtras.h"
#include "Utility.h"
+#include <__cxxabi_config.h>
#include <algorithm>
#include <cassert>
#include <cctype>
@@ -31,6 +32,11 @@
#include <type_traits>
#include <utility>
+#ifdef _LIBCXXABI_COMPILER_CLANG
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-template"
+#endif
+
DEMANGLE_NAMESPACE_BEGIN
template <class T, size_t N> class PODSmallVector {
@@ -127,8 +133,8 @@ template <class T, size_t N> class PODSmallVector {
--Last;
}
- void dropBack(size_t Index) {
- assert(Index <= size() && "dropBack() can't expand!");
+ void shrinkToSize(size_t Index) {
+ assert(Index <= size() && "shrinkToSize() can't expand!");
Last = First + Index;
}
@@ -872,21 +878,22 @@ class FunctionEncoding final : public Node {
const Node *Name;
NodeArray Params;
const Node *Attrs;
+ const Node *Requires;
Qualifiers CVQuals;
FunctionRefQual RefQual;
public:
FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_,
- const Node *Attrs_, Qualifiers CVQuals_,
- FunctionRefQual RefQual_)
+ const Node *Attrs_, const Node *Requires_,
+ Qualifiers CVQuals_, FunctionRefQual RefQual_)
: Node(KFunctionEncoding,
/*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
/*FunctionCache=*/Cache::Yes),
Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
- CVQuals(CVQuals_), RefQual(RefQual_) {}
+ Requires(Requires_), CVQuals(CVQuals_), RefQual(RefQual_) {}
template<typename Fn> void match(Fn F) const {
- F(Ret, Name, Params, Attrs, CVQuals, RefQual);
+ F(Ret, Name, Params, Attrs, Requires, CVQuals, RefQual);
}
Qualifiers getCVQuals() const { return CVQuals; }
@@ -929,6 +936,11 @@ class FunctionEncoding final : public Node {
if (Attrs != nullptr)
Attrs->print(OB);
+
+ if (Requires != nullptr) {
+ OB += " requires ";
+ Requires->print(OB);
+ }
}
};
@@ -1000,6 +1012,24 @@ struct NestedName : Node {
}
};
+struct MemberLikeFriendName : Node {
+ Node *Qual;
+ Node *Name;
+
+ MemberLikeFriendName(Node *Qual_, Node *Name_)
+ : Node(KMemberLikeFriendName), Qual(Qual_), Name(Name_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Qual, Name); }
+
+ std::string_view getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Qual->print(OB);
+ OB += "::friend ";
+ Name->print(OB);
+ }
+};
+
struct ModuleName : Node {
ModuleName *Parent;
Node *Name;
@@ -1165,6 +1195,24 @@ class SyntheticTemplateParamName final : public Node {
}
};
+class TemplateParamQualifiedArg final : public Node {
+ Node *Param;
+ Node *Arg;
+
+public:
+ TemplateParamQualifiedArg(Node *Param_, Node *Arg_)
+ : Node(KTemplateParamQualifiedArg), Param(Param_), Arg(Arg_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Param, Arg); }
+
+ Node *getArg() { return Arg; }
+
+ void printLeft(OutputBuffer &OB) const override {
+ // Don't print Param to keep the output consistent.
+ Arg->print(OB);
+ }
+};
+
/// A template type parameter declaration, 'typename T'.
class TypeTemplateParamDecl final : public Node {
Node *Name;
@@ -1180,6 +1228,26 @@ class TypeTemplateParamDecl final : public Node {
void printRight(OutputBuffer &OB) const override { Name->print(OB); }
};
+/// A constrained template type parameter declaration, 'C<U> T'.
+class ConstrainedTypeTemplateParamDecl final : public Node {
+ Node *Constraint;
+ Node *Name;
+
+public:
+ ConstrainedTypeTemplateParamDecl(Node *Constraint_, Node *Name_)
+ : Node(KConstrainedTypeTemplateParamDecl, Cache::Yes),
+ Constraint(Constraint_), Name(Name_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Constraint, Name); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ Constraint->print(OB);
+ OB += " ";
+ }
+
+ void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+};
+
/// A non-type template parameter declaration, 'int N'.
class NonTypeTemplateParamDecl final : public Node {
Node *Name;
@@ -1208,13 +1276,14 @@ class NonTypeTemplateParamDecl final : public Node {
class TemplateTemplateParamDecl final : public Node {
Node *Name;
NodeArray Params;
+ Node *Requires;
public:
- TemplateTemplateParamDecl(Node *Name_, NodeArray Params_)
+ TemplateTemplateParamDecl(Node *Name_, NodeArray Params_, Node *Requires_)
: Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_),
- Params(Params_) {}
+ Params(Params_), Requires(Requires_) {}
- template<typename Fn> void match(Fn F) const { F(Name, Params); }
+ template <typename Fn> void match(Fn F) const { F(Name, Params, Requires); }
void printLeft(OutputBuffer &OB) const override {
ScopedOverride<unsigned> LT(OB.GtIsGt, 0);
@@ -1223,7 +1292,13 @@ class TemplateTemplateParamDecl final : public Node {
OB += "> typename ";
}
- void printRight(OutputBuffer &OB) const override { Name->print(OB); }
+ void printRight(OutputBuffer &OB) const override {
+ Name->print(OB);
+ if (Requires != nullptr) {
+ OB += " requires ";
+ Requires->print(OB);
+ }
+ }
};
/// A template parameter pack declaration, 'typename ...T'.
@@ -1320,7 +1395,7 @@ class ParameterPack final : public Node {
/// A variadic template argument. This node represents an occurrence of
/// J<something>E in some <template-args>. It isn't itself unexpanded, unless
-/// one of it's Elements is. The parser inserts a ParameterPack into the
+/// one of its Elements is. The parser inserts a ParameterPack into the
/// TemplateParams table if the <template-args> this pack belongs to apply to an
/// <encoding>.
class TemplateArgumentPack final : public Node {
@@ -1386,11 +1461,13 @@ class ParameterPackExpansion final : public Node {
class TemplateArgs final : public Node {
NodeArray Params;
+ Node *Requires;
public:
- TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
+ TemplateArgs(NodeArray Params_, Node *Requires_)
+ : Node(KTemplateArgs), Params(Params_), Requires(Requires_) {}
- template<typename Fn> void match(Fn F) const { F(Params); }
+ template<typename Fn> void match(Fn F) const { F(Params, Requires); }
NodeArray getParams() { return Params; }
@@ -1399,6 +1476,7 @@ class TemplateArgs final : public Node {
OB += "<";
Params.printWithComma(OB);
OB += ">";
+ // Don't print the requires clause to keep the output simple.
}
};
@@ -1583,7 +1661,7 @@ class SpecialSubstitution final : public ExpandedSpecialSubstitution {
std::string_view SV = ExpandedSpecialSubstitution::getBaseName();
if (isInstantiation()) {
// The instantiations are typedefs that drop the "basic_" prefix.
- assert(llvm::itanium_demangle::starts_with(SV, "basic_"));
+ assert(starts_with(SV, "basic_"));
SV.remove_prefix(sizeof("basic_") - 1);
}
return SV;
@@ -1649,17 +1727,21 @@ class UnnamedTypeName : public Node {
class ClosureTypeName : public Node {
NodeArray TemplateParams;
+ const Node *Requires1;
NodeArray Params;
+ const Node *Requires2;
std::string_view Count;
public:
- ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_,
+ ClosureTypeName(NodeArray TemplateParams_, const Node *Requires1_,
+ NodeArray Params_, const Node *Requires2_,
std::string_view Count_)
: Node(KClosureTypeName), TemplateParams(TemplateParams_),
- Params(Params_), Count(Count_) {}
+ Requires1(Requires1_), Params(Params_), Requires2(Requires2_),
+ Count(Count_) {}
template<typename Fn> void match(Fn F) const {
- F(TemplateParams, Params, Count);
+ F(TemplateParams, Requires1, Params, Requires2, Count);
}
void printDeclarator(OutputBuffer &OB) const {
@@ -1669,12 +1751,22 @@ class ClosureTypeName : public Node {
TemplateParams.printWithComma(OB);
OB += ">";
}
+ if (Requires1 != nullptr) {
+ OB += " requires ";
+ Requires1->print(OB);
+ OB += " ";
+ }
OB.printOpen();
Params.printWithComma(OB);
OB.printClose();
+ if (Requires2 != nullptr) {
+ OB += " requires ";
+ Requires2->print(OB);
+ }
}
void printLeft(OutputBuffer &OB) const override {
+ // FIXME: This demangling is not particularly readable.
OB += "\'lambda";
OB += Count;
OB += "\'";
@@ -2303,6 +2395,95 @@ class IntegerLiteral : public Node {
}
};
+class RequiresExpr : public Node {
+ NodeArray Parameters;
+ NodeArray Requirements;
+public:
+ RequiresExpr(NodeArray Parameters_, NodeArray Requirements_)
+ : Node(KRequiresExpr), Parameters(Parameters_),
+ Requirements(Requirements_) {}
+
+ template<typename Fn> void match(Fn F) const { F(Parameters, Requirements); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += "requires";
+ if (!Parameters.empty()) {
+ OB += ' ';
+ OB.printOpen();
+ Parameters.printWithComma(OB);
+ OB.printClose();
+ }
+ OB += ' ';
+ OB.printOpen('{');
+ for (const Node *Req : Requirements) {
+ Req->print(OB);
+ }
+ OB += ' ';
+ OB.printClose('}');
+ }
+};
+
+class ExprRequirement : public Node {
+ const Node *Expr;
+ bool IsNoexcept;
+ const Node *TypeConstraint;
+public:
+ ExprRequirement(const Node *Expr_, bool IsNoexcept_,
+ const Node *TypeConstraint_)
+ : Node(KExprRequirement), Expr(Expr_), IsNoexcept(IsNoexcept_),
+ TypeConstraint(TypeConstraint_) {}
+
+ template <typename Fn> void match(Fn F) const {
+ F(Expr, IsNoexcept, TypeConstraint);
+ }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += " ";
+ if (IsNoexcept || TypeConstraint)
+ OB.printOpen('{');
+ Expr->print(OB);
+ if (IsNoexcept || TypeConstraint)
+ OB.printClose('}');
+ if (IsNoexcept)
+ OB += " noexcept";
+ if (TypeConstraint) {
+ OB += " -> ";
+ TypeConstraint->print(OB);
+ }
+ OB += ';';
+ }
+};
+
+class TypeRequirement : public Node {
+ const Node *Type;
+public:
+ TypeRequirement(const Node *Type_)
+ : Node(KTypeRequirement), Type(Type_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Type); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += " typename ";
+ Type->print(OB);
+ OB += ';';
+ }
+};
+
+class NestedRequirement : public Node {
+ const Node *Constraint;
+public:
+ NestedRequirement(const Node *Constraint_)
+ : Node(KNestedRequirement), Constraint(Constraint_) {}
+
+ template <typename Fn> void match(Fn F) const { F(Constraint); }
+
+ void printLeft(OutputBuffer &OB) const override {
+ OB += " requires ";
+ Constraint->print(OB);
+ OB += ';';
+ }
+};
+
template <class Float> struct FloatData;
namespace float_literal_impl {
@@ -2397,6 +2578,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
// table.
PODSmallVector<Node *, 32> Subs;
+ // A list of template argument values corresponding to a template parameter
+ // list.
using TemplateParamList = PODSmallVector<Node *, 8>;
class ScopedTemplateParamList {
@@ -2412,8 +2595,9 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
}
~ScopedTemplateParamList() {
assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists);
- Parser->TemplateParams.dropBack(OldNumTemplateParamLists);
+ Parser->TemplateParams.shrinkToSize(OldNumTemplateParamLists);
}
+ TemplateParamList *params() { return &Params; }
};
// Template parameter table. Like the above, but referenced like "T42_".
@@ -2428,12 +2612,31 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
// parameter list, the corresponding parameter list pointer will be null.
PODSmallVector<TemplateParamList *, 4> TemplateParams;
+ class SaveTemplateParams {
+ AbstractManglingParser *Parser;
+ decltype(TemplateParams) OldParams;
+ decltype(OuterTemplateParams) OldOuterParams;
+
+ public:
+ SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
+ OldParams = std::move(Parser->TemplateParams);
+ OldOuterParams = std::move(Parser->OuterTemplateParams);
+ Parser->TemplateParams.clear();
+ Parser->OuterTemplateParams.clear();
+ }
+ ~SaveTemplateParams() {
+ Parser->TemplateParams = std::move(OldParams);
+ Parser->OuterTemplateParams = std::move(OldOuterParams);
+ }
+ };
+
// Set of unresolved forward <template-param> references. These can occur in a
// conversion operator's type, and are resolved in the enclosing <encoding>.
PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;
bool TryToParseTemplateArgs = true;
bool PermitForwardTemplateReferences = false;
+ bool InConstraintExpr = false;
size_t ParsingLambdaParamsAtLevel = (size_t)-1;
unsigned NumSyntheticTemplateParameters[3] = {};
@@ -2475,13 +2678,12 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
assert(FromPosition <= Names.size());
NodeArray res =
makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
- Names.dropBack(FromPosition);
+ Names.shrinkToSize(FromPosition);
return res;
}
bool consumeIf(std::string_view S) {
- if (llvm::itanium_demangle::starts_with(
- std::string_view(First, Last - First), S)) {
+ if (starts_with(std::string_view(First, Last - First), S)) {
First += S.size();
return true;
}
@@ -2514,11 +2716,16 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
bool parseSeqId(size_t *Out);
Node *parseSubstitution();
Node *parseTemplateParam();
- Node *parseTemplateParamDecl();
+ Node *parseTemplateParamDecl(TemplateParamList *Params);
Node *parseTemplateArgs(bool TagTemplates = false);
Node *parseTemplateArg();
- /// Parse the <expr> production.
+ bool isTemplateParamDecl() {
+ return look() == 'T' &&
+ std::string_view("yptnk").find(look(1)) != std::string_view::npos;
+ }
+
+ /// Parse the <expression> production.
Node *parseExpr();
Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec);
Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec);
@@ -2531,6 +2738,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseFoldExpr();
Node *parsePointerToMemberConversionExpr(Node::Prec Prec);
Node *parseSubobjectExpr();
+ Node *parseConstraintExpr();
+ Node *parseRequiresExpr();
/// Parse the <type> production.
Node *parseType();
@@ -2569,7 +2778,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
return true;
ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx];
}
- ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
+ ForwardTemplateRefs.shrinkToSize(State.ForwardTemplateRefsBegin);
return false;
}
@@ -2633,10 +2842,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
std::string_view getSymbol() const {
std::string_view Res = Name;
if (Kind < Unnameable) {
- assert(llvm::itanium_demangle::starts_with(Res, "operator") &&
+ assert(starts_with(Res, "operator") &&
"operator name does not start with 'operator'");
Res.remove_prefix(sizeof("operator") - 1);
- if (llvm::itanium_demangle::starts_with(Res, ' '))
+ if (starts_with(Res, ' '))
Res.remove_prefix(1);
}
return Res;
@@ -2722,6 +2931,10 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) {
return make<LocalName>(Encoding, StringLitName);
}
+ // The template parameters of the inner name are unrelated to those of the
+ // enclosing context.
+ SaveTemplateParams SaveTemplateParamsScope(this);
+
if (consumeIf('d')) {
parseNumber(true);
if (!consumeIf('_'))
@@ -2777,9 +2990,9 @@ AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State,
return Res;
}
-// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>]
+// <unqualified-name> ::= [<module-name>] F? L? <operator-name> [<abi-tags>]
// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>]
-// ::= [<module-name>] L? <source-name> [<abi-tags>]
+// ::= [<module-name>] F? L? <source-name> [<abi-tags>]
// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>]
// # structured binding declaration
// ::= [<module-name>] L? DC <source-name>+ E
@@ -2789,6 +3002,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
if (getDerived().parseModuleNameOpt(Module))
return nullptr;
+ bool IsMemberLikeFriend = Scope && consumeIf('F');
+
consumeIf('L');
Node *Result;
@@ -2819,7 +3034,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(
Result = make<ModuleEntity>(Module, Result);
if (Result != nullptr)
Result = getDerived().parseAbiTags(Result);
- if (Result != nullptr && Scope != nullptr)
+ if (Result != nullptr && IsMemberLikeFriend)
+ Result = make<MemberLikeFriendName>(Scope, Result);
+ else if (Result != nullptr && Scope != nullptr)
Result = make<NestedName>(Scope, Result);
return Result;
@@ -2851,7 +3068,8 @@ bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt(
//
// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
//
-// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+// <lambda-sig> ::= <template-param-decl>* [Q <requires-clause expression>]
+// <parameter type>+ # or "v" if the lambda has no parameters
template <typename Derived, typename Alloc>
Node *
AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
@@ -2872,10 +3090,10 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
ScopedTemplateParamList LambdaTemplateParams(this);
size_t ParamsBegin = Names.size();
- while (look() == 'T' &&
- std::string_view("yptn").find(look(1)) != std::string_view::npos) {
- Node *T = parseTemplateParamDecl();
- if (!T)
+ while (getDerived().isTemplateParamDecl()) {
+ Node *T =
+ getDerived().parseTemplateParamDecl(LambdaTemplateParams.params());
+ if (T == nullptr)
return nullptr;
Names.push_back(T);
}
@@ -2906,20 +3124,38 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) {
if (TempParams.empty())
TemplateParams.pop_back();
- if (!consumeIf("vE")) {
+ Node *Requires1 = nullptr;
+ if (consumeIf('Q')) {
+ Requires1 = getDerived().parseConstraintExpr();
+ if (Requires1 == nullptr)
+ return nullptr;
+ }
+
+ if (!consumeIf("v")) {
do {
Node *P = getDerived().parseType();
if (P == nullptr)
return nullptr;
Names.push_back(P);
- } while (!consumeIf('E'));
+ } while (look() != 'E' && look() != 'Q');
}
NodeArray Params = popTrailingNodeArray(ParamsBegin);
+ Node *Requires2 = nullptr;
+ if (consumeIf('Q')) {
+ Requires2 = getDerived().parseConstraintExpr();
+ if (Requires2 == nullptr)
+ return nullptr;
+ }
+
+ if (!consumeIf('E'))
+ return nullptr;
+
std::string_view Count = parseNumber();
if (!consumeIf('_'))
return nullptr;
- return make<ClosureTypeName>(TempParams, Params, Count);
+ return make<ClosureTypeName>(TempParams, Requires1, Params, Requires2,
+ Count);
}
if (consumeIf("Ub")) {
(void)parseNumber();
@@ -2940,7 +3176,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
return nullptr;
std::string_view Name(First, Length);
First += Length;
- if (llvm::itanium_demangle::starts_with(Name, "_GLOBAL__N"))
+ if (starts_with(Name, "_GLOBAL__N"))
return make<NameType>("(anonymous namespace)");
return make<NameType>(Name);
}
@@ -3709,7 +3945,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() {
return nullptr;
// extension ::= U <objc-name> <objc-type> # objc-type<identifier>
- if (llvm::itanium_demangle::starts_with(Qual, "objcproto")) {
+ if (starts_with(Qual, "objcproto")) {
constexpr size_t Len = sizeof("objcproto") - 1;
std::string_view ProtoSourceName(Qual.data() + Len, Qual.size() - Len);
std::string_view Proto;
@@ -3956,6 +4192,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() {
case 'c':
First += 2;
return make<NameType>("decltype(auto)");
+ // ::= Dk <type-constraint> # constrained auto
+ // ::= DK <type-constraint> # constrained decltype(auto)
+ case 'k':
+ case 'K': {
+ std::string_view Kind = look(1) == 'k' ? " auto" : " decltype(auto)";
+ First += 2;
+ Node *Constraint = getDerived().parseName();
+ if (!Constraint)
+ return nullptr;
+ return make<PostfixQualifiedType>(Constraint, Kind);
+ }
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
case 'n':
First += 2;
@@ -4507,6 +4754,75 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
}
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseConstraintExpr() {
+ // Within this expression, all enclosing template parameter lists are in
+ // scope.
+ ScopedOverride<bool> SaveInConstraintExpr(InConstraintExpr, true);
+ return getDerived().parseExpr();
+}
+
+template <typename Derived, typename Alloc>
+Node *AbstractManglingParser<Derived, Alloc>::parseRequiresExpr() {
+ NodeArray Params;
+ if (consumeIf("rQ")) {
+ // <expression> ::= rQ <bare-function-type> _ <requirement>+ E
+ size_t ParamsBegin = Names.size();
+ while (!consumeIf('_')) {
+ Node *Type = getDerived().parseType();
+ if (Type == nullptr)
+ return nullptr;
+ Names.push_back(Type);
+ }
+ Params = popTrailingNodeArray(ParamsBegin);
+ } else if (!consumeIf("rq")) {
+ // <expression> ::= rq <requirement>+ E
+ return nullptr;
+ }
+
+ size_t ReqsBegin = Names.size();
+ do {
+ Node *Constraint = nullptr;
+ if (consumeIf('X')) {
+ // <requirement> ::= X <expression> [N] [R <type-constraint>]
+ Node *Expr = getDerived().parseExpr();
+ if (Expr == nullptr)
+ return nullptr;
+ bool Noexcept = consumeIf('N');
+ Node *TypeReq = nullptr;
+ if (consumeIf('R')) {
+ TypeReq = getDerived().parseName();
+ if (TypeReq == nullptr)
+ return nullptr;
+ }
+ Constraint = make<ExprRequirement>(Expr, Noexcept, TypeReq);
+ } else if (consumeIf('T')) {
+ // <requirement> ::= T <type>
+ Node *Type = getDerived().parseType();
+ if (Type == nullptr)
+ return nullptr;
+ Constraint = make<TypeRequirement>(Type);
+ } else if (consumeIf('Q')) {
+ // <requirement> ::= Q <constraint-expression>
+ //
+ // FIXME: We use <expression> instead of <constraint-expression>. Either
+ // the requires expression is already inside a constraint expression, in
+ // which case it makes no
diff erence, or we're in a requires-expression
+ // that might be partially-substituted, where the language behavior is
+ // not yet settled and clang mangles after substitution.
+ Node *NestedReq = getDerived().parseExpr();
+ if (NestedReq == nullptr)
+ return nullptr;
+ Constraint = make<NestedRequirement>(NestedReq);
+ }
+ if (Constraint == nullptr)
+ return nullptr;
+ Names.push_back(Constraint);
+ } while (!consumeIf('E'));
+
+ return make<RequiresExpr>(Params, popTrailingNodeArray(ReqsBegin));
+}
+
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <ternary operator-name> <expression> <expression> <expression>
@@ -4743,6 +5059,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return Ex;
return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary);
}
+ if (look() == 'r' && (look(1) == 'q' || look(1) == 'Q'))
+ return parseRequiresExpr();
if (consumeIf("so"))
return parseSubobjectExpr();
if (consumeIf("sp")) {
@@ -5021,29 +5339,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
}
// <encoding> ::= <function name> <bare-function-type>
+// [`Q` <requires-clause expr>]
// ::= <data name>
// ::= <special-name>
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
// The template parameters of an encoding are unrelated to those of the
// enclosing context.
- class SaveTemplateParams {
- AbstractManglingParser *Parser;
- decltype(TemplateParams) OldParams;
- decltype(OuterTemplateParams) OldOuterParams;
-
- public:
- SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) {
- OldParams = std::move(Parser->TemplateParams);
- OldOuterParams = std::move(Parser->OuterTemplateParams);
- Parser->TemplateParams.clear();
- Parser->OuterTemplateParams.clear();
- }
- ~SaveTemplateParams() {
- Parser->TemplateParams = std::move(OldParams);
- Parser->OuterTemplateParams = std::move(OldOuterParams);
- }
- } SaveTemplateParams(this);
+ SaveTemplateParams SaveTemplateParamsScope(this);
if (look() == 'G' || look() == 'T')
return getDerived().parseSpecialName();
@@ -5087,22 +5390,27 @@ Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() {
return nullptr;
}
- if (consumeIf('v'))
- return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
- Attrs, NameInfo.CVQualifiers,
- NameInfo.ReferenceQualifier);
+ NodeArray Params;
+ if (!consumeIf('v')) {
+ size_t ParamsBegin = Names.size();
+ do {
+ Node *Ty = getDerived().parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ Names.push_back(Ty);
+ } while (!IsEndOfEncoding() && look() != 'Q');
+ Params = popTrailingNodeArray(ParamsBegin);
+ }
- size_t ParamsBegin = Names.size();
- do {
- Node *Ty = getDerived().parseType();
- if (Ty == nullptr)
+ Node *Requires = nullptr;
+ if (consumeIf('Q')) {
+ Requires = getDerived().parseConstraintExpr();
+ if (!Requires)
return nullptr;
- Names.push_back(Ty);
- } while (!IsEndOfEncoding());
+ }
- return make<FunctionEncoding>(ReturnType, Name,
- popTrailingNodeArray(ParamsBegin),
- Attrs, NameInfo.CVQualifiers,
+ return make<FunctionEncoding>(ReturnType, Name, Params, Attrs, Requires,
+ NameInfo.CVQualifiers,
NameInfo.ReferenceQualifier);
}
@@ -5264,6 +5572,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() {
// ::= TL <level-1> _ <parameter-2 non-negative number> _
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
+ const char *Begin = First;
if (!consumeIf('T'))
return nullptr;
@@ -5285,6 +5594,14 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
return nullptr;
}
+ // We don't track enclosing template parameter levels well enough to reliably
+ // substitute them all within a <constraint-expression>, so print the
+ // parameter numbering instead for now.
+ // TODO: Track all enclosing template parameters and substitute them here.
+ if (InConstraintExpr) {
+ return make<NameType>(std::string_view(Begin, First - 1 - Begin));
+ }
+
// If we're in a context where this <template-param> refers to a
// <template-arg> further ahead in the mangled name (currently just conversion
// operator types), then we should only look it up in the right context.
@@ -5322,11 +5639,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParam() {
// ::= Tt <template-param-decl>* E # template parameter
// ::= Tp <template-param-decl> # parameter pack
template <typename Derived, typename Alloc>
-Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
+Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl(
+ TemplateParamList *Params) {
auto InventTemplateParamName = [&](TemplateParamKind Kind) {
unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++;
Node *N = make<SyntheticTemplateParamName>(Kind, Index);
- if (N) TemplateParams.back()->push_back(N);
+ if (N && Params)
+ Params->push_back(N);
return N;
};
@@ -5337,6 +5656,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
return make<TypeTemplateParamDecl>(Name);
}
+ if (consumeIf("Tk")) {
+ Node *Constraint = getDerived().parseName();
+ if (!Constraint)
+ return nullptr;
+ Node *Name = InventTemplateParamName(TemplateParamKind::Type);
+ if (!Name)
+ return nullptr;
+ return make<ConstrainedTypeTemplateParamDecl>(Constraint, Name);
+ }
+
if (consumeIf("Tn")) {
Node *Name = InventTemplateParamName(TemplateParamKind::NonType);
if (!Name)
@@ -5353,18 +5682,25 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
return nullptr;
size_t ParamsBegin = Names.size();
ScopedTemplateParamList TemplateTemplateParamParams(this);
- while (!consumeIf("E")) {
- Node *P = parseTemplateParamDecl();
+ Node *Requires = nullptr;
+ while (!consumeIf('E')) {
+ Node *P = parseTemplateParamDecl(TemplateTemplateParamParams.params());
if (!P)
return nullptr;
Names.push_back(P);
+ if (consumeIf('Q')) {
+ Requires = getDerived().parseConstraintExpr();
+ if (Requires == nullptr || !consumeIf('E'))
+ return nullptr;
+ break;
+ }
}
- NodeArray Params = popTrailingNodeArray(ParamsBegin);
- return make<TemplateTemplateParamDecl>(Name, Params);
+ NodeArray InnerParams = popTrailingNodeArray(ParamsBegin);
+ return make<TemplateTemplateParamDecl>(Name, InnerParams, Requires);
}
if (consumeIf("Tp")) {
- Node *P = parseTemplateParamDecl();
+ Node *P = parseTemplateParamDecl(Params);
if (!P)
return nullptr;
return make<TemplateParamPackDecl>(P);
@@ -5378,6 +5714,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateParamDecl() {
// ::= <expr-primary> # simple expressions
// ::= J <template-arg>* E # argument pack
// ::= LZ <encoding> E # extension
+// ::= <template-param-decl> <template-arg>
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
switch (look()) {
@@ -5412,6 +5749,18 @@ Node *AbstractManglingParser<Derived, Alloc>::parseTemplateArg() {
// ::= <expr-primary> # simple expressions
return getDerived().parseExprPrimary();
}
+ case 'T': {
+ // Either <template-param> or a <template-param-decl> <template-arg>.
+ if (!getDerived().isTemplateParamDecl())
+ return getDerived().parseType();
+ Node *Param = getDerived().parseTemplateParamDecl(nullptr);
+ if (!Param)
+ return nullptr;
+ Node *Arg = getDerived().parseTemplateArg();
+ if (!Arg)
+ return nullptr;
+ return make<TemplateParamQualifiedArg>(Param, Arg);
+ }
default:
return getDerived().parseType();
}
@@ -5434,30 +5783,39 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
}
size_t ArgsBegin = Names.size();
+ Node *Requires = nullptr;
while (!consumeIf('E')) {
if (TagTemplates) {
- auto OldParams = std::move(TemplateParams);
Node *Arg = getDerived().parseTemplateArg();
- TemplateParams = std::move(OldParams);
if (Arg == nullptr)
return nullptr;
Names.push_back(Arg);
Node *TableEntry = Arg;
+ if (Arg->getKind() == Node::KTemplateParamQualifiedArg) {
+ TableEntry =
+ static_cast<TemplateParamQualifiedArg *>(TableEntry)->getArg();
+ }
if (Arg->getKind() == Node::KTemplateArgumentPack) {
TableEntry = make<ParameterPack>(
static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
if (!TableEntry)
return nullptr;
}
- TemplateParams.back()->push_back(TableEntry);
+ OuterTemplateParams.push_back(TableEntry);
} else {
Node *Arg = getDerived().parseTemplateArg();
if (Arg == nullptr)
return nullptr;
Names.push_back(Arg);
}
+ if (consumeIf('Q')) {
+ Requires = getDerived().parseConstraintExpr();
+ if (!Requires || !consumeIf('E'))
+ return nullptr;
+ break;
+ }
}
- return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
+ return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin), Requires);
}
// <mangled-name> ::= _Z <encoding>
@@ -5509,4 +5867,8 @@ struct ManglingParser : AbstractManglingParser<ManglingParser<Alloc>, Alloc> {
DEMANGLE_NAMESPACE_END
+#ifdef _LIBCXXABI_COMPILER_CLANG
+#pragma clang diagnostic pop
+#endif
+
#endif // DEMANGLE_ITANIUMDEMANGLE_H
diff --git a/llvm/include/llvm/Demangle/ItaniumNodes.def b/llvm/include/llvm/Demangle/ItaniumNodes.def
index c0e277d554ccfad..12cfa70f93e6308 100644
--- a/llvm/include/llvm/Demangle/ItaniumNodes.def
+++ b/llvm/include/llvm/Demangle/ItaniumNodes.def
@@ -36,6 +36,7 @@ NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
+NODE(MemberLikeFriendName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
@@ -44,7 +45,9 @@ NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
+NODE(TemplateParamQualifiedArg)
NODE(TypeTemplateParamDecl)
+NODE(ConstrainedTypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
@@ -91,5 +94,9 @@ NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
+NODE(RequiresExpr)
+NODE(ExprRequirement)
+NODE(TypeRequirement)
+NODE(NestedRequirement)
#undef NODE
More information about the cfe-commits
mailing list