diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 43b113d00a509..3cf2d4f6cfb30 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 different 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 `_), + (`#49884 `_), and + (`#61273 `_) ABI Changes in This Version --------------------------- diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h index 6f38b2c4b0571..4f34799bad050 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) const { @@ -522,19 +524,22 @@ class RequiresExpr final : public Expr, } RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, - RequiresExprBodyDecl *Body, + RequiresExprBodyDecl *Body, SourceLocation LParenLoc, ArrayRef LocalParameters, + SourceLocation RParenLoc, ArrayRef Requirements, SourceLocation RBraceLoc); RequiresExpr(ASTContext &C, EmptyShell Empty, unsigned NumLocalParameters, unsigned NumRequirements); public: - static RequiresExpr * - Create(ASTContext &C, SourceLocation RequiresKWLoc, - RequiresExprBodyDecl *Body, ArrayRef LocalParameters, - ArrayRef Requirements, - SourceLocation RBraceLoc); + static RequiresExpr *Create(ASTContext &C, SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + SourceLocation LParenLoc, + ArrayRef LocalParameters, + SourceLocation RParenLoc, + ArrayRef 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 fb073bf16bbf2..e0e95f6d26f45 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 differ 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 47379e00a7445..712db0a3dd895 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 LocalParameters, + SourceLocation RParenLoc, ArrayRef Requirements, SourceLocation ClosingBraceLoc); diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index 2aa15049a7ff2..0704630c0fc26 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 LocalParameters, + SourceLocation RParenLoc, ArrayRef 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 LocalParameters, - ArrayRef Requirements, - SourceLocation RBraceLoc) { +RequiresExpr *RequiresExpr::Create( + ASTContext &C, SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, + SourceLocation LParenLoc, ArrayRef LocalParameters, + SourceLocation RParenLoc, ArrayRef Requirements, + SourceLocation RBraceLoc) { void *Mem = C.Allocate(totalSizeToAlloc( 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 53963d2a91752..3bbc0a5767ff4 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 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 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(D)) + if (const auto *FD = dyn_cast(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(*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 should not include an X/E around // . 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(GD.getDecl()); - // ::= [] + // ::= [] [F] // ::= - // ::= [] + // ::= [] [F] // ::= [] DC * 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(ND); + auto *FTD = dyn_cast(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(ND); bool IsRegCall = FD && FD->getType()->castAs()->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 // now, with no substitutions and no . if (Decl *Context = Block->getBlockManglingContextDecl()) { - if (getASTContext().getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver12 && + if (isCompatibleWith(LangOptions::ClangABI::Ver12) && (isa(Context) || isa(Context)) && Context->getDeclContext()->isRecord()) { const auto *ND = cast(Context); @@ -1940,15 +1980,25 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) { } // -// ::= Ty # template type parameter -// ::= Tn # template non-type parameter -// ::= Tt * E # template template parameter -// ::= Tp # template parameter pack +// ::= Ty # template type parameter +// ::= Tk [] # constrained type parameter +// ::= Tn # template non-type parameter +// ::= Tt * E [Q ] +// # template template parameter +// ::= Tp # 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(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(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(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 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 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 // now, with no substitutions. if (Decl *Context = Lambda->getLambdaContextDecl()) { - if (getASTContext().getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver12 && + if (isCompatibleWith(LangOptions::ClangABI::Ver12) && (isa(Context) || isa(Context)) && !isa(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(); 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()) { // ::= 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()) { + // 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)); + // ::= z # ellipsis + if (Proto->isVariadic()) + Out << 'z'; + } - if (FD) { - if (auto *Attr = FD->getParamDecl(I)->getAttr()) { - // 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); - - // ::= z # ellipsis - if (Proto->isVariadic()) - Out << 'z'; } // ::= @@ -4198,7 +4284,15 @@ void CXXNameMangler::mangleType(const AutoType *T) { "shouldn't need to mangle __auto_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(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(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(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) { // ::= @@ -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(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__ differently than alignof. (They // have acted differently 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: { - // ::= L E # external name - Out << "L_Z"; auto *CSE = cast(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(E); + // This is a primary-expression in the C++ grammar, but does not have an + // 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(ResolvedTemplate)) { + auto *RD = dyn_cast(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 mangling with a + /// . 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(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(Param)) + return NTTP->getType()->isInstantiationDependentType() || + NTTP->getType()->getContainedDeducedType(); + + // For a template template parameter, the template-head might differ from + // that of the template. + auto *TTP = cast(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 difference 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 &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(ResolvedTemplate)) { - auto *RD = dyn_cast(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(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) { - // ::= I + E + // ::= I + [Q ] 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) { - // ::= I + E + // ::= I + [Q ] 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 Args) { - // ::= I + E + // ::= I + [Q ] 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. + // + // ::= + // + // Clang 17 and before did not do this. + mangleTemplateParamDecl(ArgInfo.TemplateParameterToMangle); + } + + mangleTemplateArg(A, ArgInfo.NeedExactType); +} + void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) { // ::= # type or template // ::= X 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()->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 ffb4f30db0243..9293b910c57d6 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 d2715db95f528..99b4931004546 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 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 77289595972e3..c147cc5293fd7 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 LocalParameters, - ArrayRef Requirements, - SourceLocation ClosingBraceLoc) { - auto *RE = RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, - Requirements, ClosingBraceLoc); +ExprResult Sema::ActOnRequiresExpr( + SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, + SourceLocation LParenLoc, ArrayRef LocalParameters, + SourceLocation RParenLoc, ArrayRef 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 c723e47ffca8e..00a36696cf904 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 603a23275889f..0fc5ad8e3bde6 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 Reqs, + bool TransformRequiresExprRequirements( + ArrayRef Reqs, llvm::SmallVectorImpl &Transformed); concepts::TypeRequirement * TransformTypeRequirement(concepts::TypeRequirement *Req); @@ -3616,11 +3617,14 @@ class TreeTransform { /// Subclasses may override this routine to provide different behavior. ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, + SourceLocation LParenLoc, ArrayRef LocalParameters, + SourceLocation RParenLoc, ArrayRef 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::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 diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index b9d9349839299..8edb04f4f8190 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()); + 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 94d3f9430d27a..125ca17c0c121 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 e60e6348a5f6d..dec26aeaeca46 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 struct S {}; template concept C = true; template S> f0() { return S>{}; } template S> f0<>(); -// CHECK: @_ZN5test12f0IiEENS_1SIL_ZNS_1CIT_EEEEEv( +// CHECK: @_ZN5test12f0IiEENS_1SIX1CIT_EEEEv( +// CLANG16: @_ZN5test12f0IiEENS_1SIL_ZNS_1CIT_EEEEEv( } template struct S {}; template concept C = true; +template concept D = true; + +template S> f0a() { return S>{}; } +template S> f0a<>(); +// CHECK: @_Z3f0aIiE1SIXsr5test1E1CIT_EEEv( +// CLANG16: @_Z3f0aIiE1SIL_ZN5test11CIT_EEEEv( + template S> f0() { return S>{}; } template S> f0<>(); -// CHECK: @_Z2f0IiE1SIL_Z1CIT_EEEv( +// CHECK: @_Z2f0IiE1SIX1CIT_EEEv( +// CLANG16: @_Z2f0IiE1SIL_Z1CIT_EEEv( + +template concept True = true; + +namespace test2 { + // Member-like friends. + template struct A { + friend void f(...) requires True {} + + template + friend void g(...) requires True && True {} + + template + friend void h(...) requires True {} + + template requires True && True + friend void i(...) {} + + template requires True + friend void j(...) {} + + template requires True + friend void k(...) {} + + template + friend void l(...) {} + }; + + A 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 void d() {} + template void d<0>(); + // CHECK: define {{.*}}@_ZN5test31dITnDaLi0EEEvv( + // CLANG16: define {{.*}}@_ZN5test31dILi0EEEvv( + + template void e() {} + template void e<0>(); + // CHECK: define {{.*}}@_ZN5test31eITnDcLi0EEEvv( + // CLANG16: define {{.*}}@_ZN5test31eILi0EEEvv( + + // Constrained auto. + template void f() {} + template void f<0>(); + // CHECK: define {{.*}}@_ZN5test31fITnDk1CLi0EEEvv( + // CLANG16: define {{.*}}@_ZN5test31fILi0EEEvv( + + template auto> void g() {} + template void g<0>(); + // CHECK: define {{.*}}@_ZN5test31gITnDk1DIiELi0EEEvv( + // CLANG16: define {{.*}}@_ZN5test31gILi0EEEvv( + + template auto> void h() {} + template void h(); + // CHECK: define {{.*}}@_ZN5test31hIiTnDk1DIT_ELi0EEEvv( + // CLANG16: define {{.*}}@_ZN5test31hIiLi0EEEvv( + + template void i(decltype(new C auto(T()))) {} + template void i(int*); + // CHECK: define {{.*}}@_ZN5test31iIiEEvDTnw_Dk1CpicvT__EEE( + // CLANG16: define {{.*}}@_ZN5test31iIiEEvDTnw_DapicvT__EEE( + + template void j(decltype(new C decltype(auto)(T()))) {} + template void j(int*); + // CHECK: define {{.*}}@_ZN5test31jIiEEvDTnw_DK1CpicvT__EEE( + // CLANG16: define {{.*}}@_ZN5test31jIiEEvDTnw_DcpicvT__EEE( +} + +namespace test4 { + // Constrained type parameters. + template void f() {} + template void f(); + // CHECK: define {{.*}}@_ZN5test41fITk1CiEEvv( + // CLANG16: define {{.*}}@_ZN5test41fIiEEvv( + + template> void g() {} + template void g(); + // CHECK: define {{.*}}@_ZN5test41gITk1DIiEiEEvv( + // CLANG16: define {{.*}}@_ZN5test41gIiEEvv( +} + +namespace test5 { + // Exact-match vs non-exact-match template template parameters. + template struct X {}; + template requires C struct Y {}; + template struct Z {}; + + template typename> void f() {} + // CHECK: define {{.*}}@_ZN5test51fINS_1XEEEvv( + template void f(); + // CHECK: define {{.*}}@_ZN5test51fITtTyTnTL0__ENS_1YEEEvv( + template void f(); + // CHECK: define {{.*}}@_ZN5test51fITtTyTnTL0__ENS_1ZEEEvv( + template void f(); + + template requires C typename> void g() {} + // CHECK: define {{.*}}@_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1XEEEvv( + template void g(); + // CHECK: define {{.*}}@_ZN5test51gINS_1YEEEvv( + template void g(); + // CHECK: define {{.*}}@_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1ZEEEvv( + template void g(); + + template typename> void h() {} + // CHECK: define {{.*}}@_ZN5test51hITtTk1CTnTL0__ENS_1XEEEvv( + template void h(); + // CHECK: define {{.*}}@_ZN5test51hITtTk1CTnTL0__ENS_1YEEEvv( + template void h(); + // CHECK: define {{.*}}@_ZN5test51hINS_1ZEEEvv( + template void h(); + + // Packs must match the first argument. + template typename...> void i() {} + // CHECK: define {{.*}}@_ZN5test51iITpTtTk1CTnTL0__EJNS_1XENS_1YENS_1ZEEEEvv( + template void i(); + // CHECK: define {{.*}}@_ZN5test51iITpTtTk1CTnTL0__EJNS_1YENS_1ZENS_1XEEEEvv( + template void i(); + // CHECK: define {{.*}}@_ZN5test51iIJNS_1ZENS_1XENS_1YEEEEvv( + template void i(); + + template struct A {}; + template struct B {}; + + template typename> void p() {} + // CHECK: define {{.*}}@_ZN5test51pINS_1AEEEvv( + // CLANG16: define {{.*}}@_ZN5test51pINS_1AEEEvv( + template void p(); + // CHECK: define {{.*}}@_ZN5test51pITtTpTyENS_1BEEEvv( + // CLANG16: define {{.*}}@_ZN5test51pINS_1BEEEvv( + template void p(); + + template typename> void q() {} + // CHECK: define {{.*}}@_ZN5test51qITtTyTyENS_1AEEEvv( + // CLANG16: define {{.*}}@_ZN5test51qINS_1AEEEvv( + template void q(); + // CHECK: define {{.*}}@_ZN5test51qINS_1BEEEvv( + // CLANG16: define {{.*}}@_ZN5test51qINS_1BEEEvv( + template void q(); +} + +namespace test6 { + // Abbreviated function templates. + void f(C auto) {} + // CHECK: define {{.*}}@_ZN5test61fITk1CiEEvT_( + // CLANG16: define {{.*}}@_ZN5test61fIiEEvT_( + template void f(int); + + template + void g(D auto) {} + // CHECK: define {{.*}}@_ZN5test61gIiTk1DIT_EiEEvT0_( + // CLANG16: define {{.*}}@_ZN5test61gIiiEEvT0_( + template void g(int); +} + +namespace test7 { + // Constrained lambdas. + template void f() { + // Ensure that requires-clauses affect lambda numbering. + // CHECK-LABEL: define {{.*}}@_ZN5test71fIiEEvv( + // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E_clIiiEEDaS3_Q1CIDtfp_EE( + ([] requires C && C (auto x) requires C {}).template operator()(0); + // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E0_clIiiEEDaS3_Qaa1CIDtfp_EELb1E( + ([] requires C && C (auto x) requires C && true {}).template operator()(0); + // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E1_clIiiEEDaS3_Q1CIDtfp_EE( + ([] requires C && C (auto x) requires C {}).template operator()(0); + // CHECK: call {{.*}}@_ZZN5test71fIiEEvvENKUlTyT0_E_clIiiEEDaS1_( + ([] (auto x){}).template operator()(0); + } + template void f(); +} diff --git a/clang/test/CodeGenCXX/mangle-exprs.cpp b/clang/test/CodeGenCXX/mangle-exprs.cpp index e7008eee4643d..88406d7fe6d80 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_(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_(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 7577ef8f2561f..78fa7c378c88d 100644 --- a/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp +++ b/clang/test/CodeGenCXX/mangle-nttp-anon-union.cpp @@ -74,40 +74,40 @@ template void dummy(){} void uses() { // Zero init'ed cases. dummy{}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper1IiEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper1IiEEEEvv // DEMANGLED: call void @void dummy{}>()() dummy{}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper2IfEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper2IfEEEEvv // DEMANGLED: call void @void dummy{}>()() dummy{}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper3IsEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper3IsEEEEvv // DEMANGLED: call void @void dummy{}>()() dummy{}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper4IdEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper4IdEEEEvv // DEMANGLED: call void @void dummy{}>()() dummy{}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper5IxEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper5IxEEEEvv // DEMANGLED: call void @void dummy{}>()() dummy{}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper6IiEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper6IiEEEEvv // DEMANGLED: call void @void dummy{}>()() dummy{123.0}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper1IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper1IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv // DEMANGLED: call void @void dummy{wrapper1::'unnamed'{.RightName = wrapper1::'unnamed'::'unnamed'{0x1.ec{{.*}}p+6}}}>()() dummy{123.0}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper2IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper2IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_ELd405ec00000000000EEEEEEvv // DEMANGLED: call void @void dummy{wrapper2::'unnamed'{.RightName = wrapper2::'unnamed'::'unnamed'{0x1.ec{{.*}}p+6}}}>()() dummy{123, 456}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper3IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Etl4BaseLi123EELd407c800000000000EEEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper3IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Etl4BaseLi123EELd407c800000000000EEEEEEvv // DEMANGLED: call void @void dummy{wrapper3::'unnamed'{.RightName = wrapper3::'unnamed'::'unnamed'{Base{123}, 0x1.c8{{.*}}p+8}}}>()() dummy{123}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper4IdEtlNS1_Ut_Edi9RightNameLi123EEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper4IdEtlNS1_Ut_Edi9RightNameLi123EEEEEvv // DEMANGLED: call void @void dummy{wrapper4::'unnamed'{.RightName = 123}}>()() dummy{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::'unnamed'{.RightName = wrapper5::'unnamed'::'unnamed'{wrapper5::'unnamed'::'unnamed'::'unnamed'{0x1.ec{{.*}}p+6}, 0x1.c8{{.*}}p+8}}}>()() dummy{1}>(); - // CHECK: call void @_Z5dummyIXtl8wrapper6IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd3ff0000000000000EEEEEEvv + // CHECK: call void @_Z5dummyITnDaXtl8wrapper6IdEtlNS1_Ut_Edi9RightNametlNS2_Ut_Edi9RightNameLd3ff0000000000000EEEEEEvv // DEMANGELD: call void @void dummy{wrapper6::'unnamed'{.RightName = wrapper6::'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 0000000000000..9897b440a6644 --- /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 concept SmallerThan = sizeof(T) < N; +template concept Small = SmallerThan; + +template struct X { using type = T; }; + +template 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; + typename X::type; + typename X; + // nested-requirement + requires SmallerThan; +} {} +// CHECK: define {{.*}}@_Z1fIiEviQrqXcvT__EXfp_Xeqfp_cvS0__EXplcvS0__ELi1ER5SmallXmicvS0__ELi1ENXmlcvS0__ELi2ENR11SmallerThanILi1234EETS0_T1XIS0_ETNS3_4typeETS2_IiEQ11SmallerThanIS0_Li256EEE( +template void f(int); + +template 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); diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp index 7611bae5dbd69..52aefa8dfc2b9 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 void test() {} void use() { - // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv( + // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIFivETnT_XadL_ZNS_L1fEvEEEEvv( test(); - // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRFivEL_ZNS_L1fEvEEEvv( + // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRFivETnT_L_ZNS_L1fEvEEEvv( test(); - // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv( + // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIPKiTnT_XadL_ZNS_L1nEEEEEvv( test(); - // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRKiL_ZNS_L1nEEEEvv( + // CHECK-LABEL: define internal {{.*}}void @_ZN6test124testIRKiTnT_L_ZNS_L1nEEEEvv( test(); } } diff --git a/clang/test/CodeGenCXX/matrix-type.cpp b/clang/test/CodeGenCXX/matrix-type.cpp index 21255f67c61c5..4d94c281ae8c4 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 56ebc78637bc5..2926d557a9038 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 e96fee18b27a3..6fdfe38bd0f1f 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -133,8 +133,8 @@ template 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 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 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 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 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 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 void match(Fn F) const { F(Name, Params); } + template void match(Fn F) const { F(Name, Params, Requires); } void printLeft(OutputBuffer &OB) const override { ScopedOverride 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 /// JE in some . 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 this pack belongs to apply to an /// . 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 void match(Fn F) const { F(Params); } + template 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 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 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 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 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 void match(Fn F) const { F(Constraint); } + + void printLeft(OutputBuffer &OB) const override { + OB += " requires "; + Constraint->print(OB); + OB += ';'; + } +}; + template struct FloatData; namespace float_literal_impl { @@ -2403,6 +2578,8 @@ template struct AbstractManglingParser { // table. PODSmallVector Subs; + // A list of template argument values corresponding to a template parameter + // list. using TemplateParamList = PODSmallVector; class ScopedTemplateParamList { @@ -2418,8 +2595,9 @@ template 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 struct AbstractManglingParser { // parameter list, the corresponding parameter list pointer will be null. PODSmallVector 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 references. These can occur in a // conversion operator's type, and are resolved in the enclosing . PODSmallVector ForwardTemplateRefs; bool TryToParseTemplateArgs = true; bool PermitForwardTemplateReferences = false; + bool InConstraintExpr = false; size_t ParsingLambdaParamsAtLevel = (size_t)-1; unsigned NumSyntheticTemplateParameters[3] = {}; @@ -2481,7 +2678,7 @@ template 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 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 production. + bool isTemplateParamDecl() { + return look() == 'T' && + std::string_view("yptnk").find(look(1)) != std::string_view::npos; + } + + /// Parse the 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 struct AbstractManglingParser { Node *parseFoldExpr(); Node *parsePointerToMemberConversionExpr(Node::Prec Prec); Node *parseSubobjectExpr(); + Node *parseConstraintExpr(); + Node *parseRequiresExpr(); /// Parse the production. Node *parseType(); @@ -2574,7 +2778,7 @@ template 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::parseLocalName(NameState *State) { return make(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::parseUnscopedName(NameState *State, return Res; } -// ::= [] L? [] +// ::= [] F? L? [] // ::= [] [] -// ::= [] L? [] +// ::= [] F? L? [] // ::= [] L? [] // # structured binding declaration // ::= [] L? DC + E @@ -2794,6 +3002,8 @@ Node *AbstractManglingParser::parseUnqualifiedName( if (getDerived().parseModuleNameOpt(Module)) return nullptr; + bool IsMemberLikeFriend = Scope && consumeIf('F'); + consumeIf('L'); Node *Result; @@ -2824,7 +3034,9 @@ Node *AbstractManglingParser::parseUnqualifiedName( Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); - if (Result != nullptr && Scope != nullptr) + if (Result != nullptr && IsMemberLikeFriend) + Result = make(Scope, Result); + else if (Result != nullptr && Scope != nullptr) Result = make(Scope, Result); return Result; @@ -2856,7 +3068,8 @@ bool AbstractManglingParser::parseModuleNameOpt( // // ::= Ul E [ ] _ // -// ::= + # Parameter types or "v" if the lambda has no parameters +// ::= * [Q ] +// + # or "v" if the lambda has no parameters template Node * AbstractManglingParser::parseUnnamedTypeName(NameState *State) { @@ -2877,10 +3090,10 @@ AbstractManglingParser::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::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(TempParams, Params, Count); + return make(TempParams, Requires1, Params, Requires2, + Count); } if (consumeIf("Ub")) { (void)parseNumber(); @@ -3961,6 +4192,17 @@ Node *AbstractManglingParser::parseType() { case 'c': First += 2; return make("decltype(auto)"); + // ::= Dk # constrained auto + // ::= DK # 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(Constraint, Kind); + } // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) case 'n': First += 2; @@ -4512,6 +4754,75 @@ Node *AbstractManglingParser::parseSubobjectExpr() { Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); } +template +Node *AbstractManglingParser::parseConstraintExpr() { + // Within this expression, all enclosing template parameter lists are in + // scope. + ScopedOverride SaveInConstraintExpr(InConstraintExpr, true); + return getDerived().parseExpr(); +} + +template +Node *AbstractManglingParser::parseRequiresExpr() { + NodeArray Params; + if (consumeIf("rQ")) { + // ::= rQ _ + 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")) { + // ::= rq + E + return nullptr; + } + + size_t ReqsBegin = Names.size(); + do { + Node *Constraint = nullptr; + if (consumeIf('X')) { + // ::= X [N] [R ] + 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(Expr, Noexcept, TypeReq); + } else if (consumeIf('T')) { + // ::= T + Node *Type = getDerived().parseType(); + if (Type == nullptr) + return nullptr; + Constraint = make(Type); + } else if (consumeIf('Q')) { + // ::= Q + // + // FIXME: We use instead of . Either + // the requires expression is already inside a constraint expression, in + // which case it makes no difference, 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(NestedReq); + } + if (Constraint == nullptr) + return nullptr; + Names.push_back(Constraint); + } while (!consumeIf('E')); + + return make(Params, popTrailingNodeArray(ReqsBegin)); +} + // ::= // ::= // ::= @@ -4748,6 +5059,8 @@ Node *AbstractManglingParser::parseExpr() { return Ex; return make("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::parseSpecialName() { } // ::= +// [`Q` ] // ::= // ::= template Node *AbstractManglingParser::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::parseEncoding() { return nullptr; } - if (consumeIf('v')) - return make(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(ReturnType, Name, - popTrailingNodeArray(ParamsBegin), - Attrs, NameInfo.CVQualifiers, + return make(ReturnType, Name, Params, Attrs, Requires, + NameInfo.CVQualifiers, NameInfo.ReferenceQualifier); } @@ -5269,6 +5572,7 @@ Node *AbstractManglingParser::parseSubstitution() { // ::= TL _ _ template Node *AbstractManglingParser::parseTemplateParam() { + const char *Begin = First; if (!consumeIf('T')) return nullptr; @@ -5290,6 +5594,14 @@ Node *AbstractManglingParser::parseTemplateParam() { return nullptr; } + // We don't track enclosing template parameter levels well enough to reliably + // substitute them all within a , so print the + // parameter numbering instead for now. + // TODO: Track all enclosing template parameters and substitute them here. + if (InConstraintExpr) { + return make(std::string_view(Begin, First - 1 - Begin)); + } + // If we're in a context where this refers to a // 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::parseTemplateParam() { // ::= Tt * E # template parameter // ::= Tp # parameter pack template -Node *AbstractManglingParser::parseTemplateParamDecl() { +Node *AbstractManglingParser::parseTemplateParamDecl( + TemplateParamList *Params) { auto InventTemplateParamName = [&](TemplateParamKind Kind) { unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++; Node *N = make(Kind, Index); - if (N) TemplateParams.back()->push_back(N); + if (N && Params) + Params->push_back(N); return N; }; @@ -5342,6 +5656,16 @@ Node *AbstractManglingParser::parseTemplateParamDecl() { return make(Name); } + if (consumeIf("Tk")) { + Node *Constraint = getDerived().parseName(); + if (!Constraint) + return nullptr; + Node *Name = InventTemplateParamName(TemplateParamKind::Type); + if (!Name) + return nullptr; + return make(Constraint, Name); + } + if (consumeIf("Tn")) { Node *Name = InventTemplateParamName(TemplateParamKind::NonType); if (!Name) @@ -5358,18 +5682,25 @@ Node *AbstractManglingParser::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(Name, Params); + NodeArray InnerParams = popTrailingNodeArray(ParamsBegin); + return make(Name, InnerParams, Requires); } if (consumeIf("Tp")) { - Node *P = parseTemplateParamDecl(); + Node *P = parseTemplateParamDecl(Params); if (!P) return nullptr; return make(P); @@ -5383,6 +5714,7 @@ Node *AbstractManglingParser::parseTemplateParamDecl() { // ::= # simple expressions // ::= J * E # argument pack // ::= LZ E # extension +// ::= template Node *AbstractManglingParser::parseTemplateArg() { switch (look()) { @@ -5417,6 +5749,18 @@ Node *AbstractManglingParser::parseTemplateArg() { // ::= # simple expressions return getDerived().parseExprPrimary(); } + case 'T': { + // Either or a . + 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(Param, Arg); + } default: return getDerived().parseType(); } @@ -5439,30 +5783,39 @@ AbstractManglingParser::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(TableEntry)->getArg(); + } if (Arg->getKind() == Node::KTemplateArgumentPack) { TableEntry = make( static_cast(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(popTrailingNodeArray(ArgsBegin)); + return make(popTrailingNodeArray(ArgsBegin), Requires); } // ::= _Z diff --git a/libcxxabi/src/demangle/ItaniumNodes.def b/libcxxabi/src/demangle/ItaniumNodes.def index f615cb9fadb05..74dc7097c1b30 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 471808db5d5b8..47cc29b2430e7 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(decltype(__uuidof(TestStruct)))"}, {"_Z15test_uuidofExprI9HasMemberEvDTu8__uuidofXsrT_6memberEEE", "void test_uuidofExpr(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'($T)::operator()(x) const"}, {"_ZNK1xMUlTnPA3_ivE_clILS0_0EEEDav", "auto x::'lambda'()::operator()<(int [3])0>() const"}, {"_ZNK1xMUlTyTtTyTnT_TpTnPA3_TL0__ETpTyvE_clIi1XJfEEEDav", "auto x::'lambda' typename $TT, typename ...$T1>()::operator()() 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(int&&)::'lambda'(int&&, auto...)>::operator()<>()"}, {"_ZZZZN6abcdef9abcdefghi29abcdefabcdefabcdefabcefabcdef27xxxxxxxxxxxxxxxxxxxxxxxxxxxEN4absl8DurationERKNSt3__u12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPNS1_19yyyyyyyyyyyyyyyyyyyEENK3$_5clEvENKUlvE_clEvE6zzzzzz", "abcdef::abcdefghi::abcdefabcdefabcdefabcefabcdef::xxxxxxxxxxxxxxxxxxxxxxxxxxx(absl::Duration, std::__u::basic_string, std::__u::allocator> 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(decltype(C::'lambda'(int, auto){}))"}, - // C++2a class type non-type template parameters: + // C++20 class type non-type template parameters: {"_Z1fIXtl1BLPi0ELi1EEEEvv", "void f()"}, {"_Z1fIXtl1BLPi32EEEEvv", "void f()"}, {"_Z1fIXtl1BrcPiLi0EEEEvv", "void f(0)}>()"}, @@ -30089,6 +30091,51 @@ const char* cases[][2] = {"_ZW1ML4Oink", "Oink@M"}, {"_ZW1ML1fi", "f@M(int)"}, + // C++20 concepts, see https://github.com/itanium-cxx-abi/cxx-abi/issues/24. + {"_Z2f0IiE1SIX1CIT_EEEv", "S> f0()"}, + {"_ZN5test21AIiEF1fEzQ4TrueIT_E", "test2::A::friend f(...) requires True"}, + {"_ZN5test2F1gIvEEvzQaa4TrueIT_E4TrueITL0__E", "void test2::friend g(...) requires True && True"}, + {"_ZN5test21hIvEEvzQ4TrueITL0__E", "void test2::h(...) requires True"}, + {"_ZN5test2F1iIvQaa4TrueIT_E4TrueITL0__EEEvz", "void test2::friend i(...)"}, + {"_ZN5test21jIvQ4TrueITL0__EEEvz", "void test2::j(...)"}, + {"_ZN5test2F1kITk4TruevQ4TrueIT_EEEvz", "void test2::friend k(...)"}, + {"_ZN5test21lITk4TruevEEvz", "void test2::l(...)"}, + {"_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()"}, + {"_ZN5test31iIiEEvDTnw_Dk1CpicvT__EEE", "void test3::i(decltype(new C auto((int)())))"}, + {"_ZN5test31jIiEEvDTnw_DK1CpicvT__EEE", "void test3::j(decltype(new C decltype(auto)((int)())))"}, + {"_ZN5test41fITk1CiEEvv", "void test4::f()"}, + {"_ZN5test41gITk1DIiEiEEvv", "void test4::g()"}, + {"_ZN5test51fINS_1XEEEvv", "void test5::f()"}, + {"_ZN5test51fITtTyTnTL0__ENS_1YEEEvv", "void test5::f()"}, + {"_ZN5test51fITtTyTnTL0__ENS_1ZEEEvv", "void test5::f()"}, + {"_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1XEEEvv", "void test5::g()"}, + {"_ZN5test51gINS_1YEEEvv", "void test5::g()"}, + {"_ZN5test51gITtTyTnTL0__Q1CIS1_EENS_1ZEEEvv", "void test5::g()"}, + {"_ZN5test51hITtTk1CTnTL0__ENS_1XEEEvv", "void test5::h()"}, + {"_ZN5test51hITtTk1CTnTL0__ENS_1YEEEvv", "void test5::h()"}, + {"_ZN5test51hINS_1ZEEEvv", "void test5::h()"}, + {"_ZN5test51iITpTtTk1CTnTL0__EJNS_1XENS_1YENS_1ZEEEEvv", "void test5::i()"}, + {"_ZN5test51iITpTtTk1CTnTL0__EJNS_1YENS_1ZENS_1XEEEEvv", "void test5::i()"}, + {"_ZN5test51iIJNS_1ZENS_1XENS_1YEEEEvv", "void test5::i()"}, + {"_ZN5test51pINS_1AEEEvv", "void test5::p()"}, + {"_ZN5test51pITtTpTyENS_1BEEEvv", "void test5::p()"}, + {"_ZN5test51qITtTyTyENS_1AEEEvv", "void test5::q()"}, + {"_ZN5test51qINS_1BEEEvv", "void test5::q()"}, + {"_ZN5test61fITk1CiEEvT_", "void test6::f(int)"}, + {"_ZN5test61gIiTk1DIT_EiEEvT0_", "void test6::g(int)"}, + {"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E_clIiiEEDaS3_Q1CIDtfp_EE", "auto void test7::f()::'lambda' requires C && C (auto)::operator()(auto) const requires C"}, + {"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E0_clIiiEEDaS3_Qaa1CIDtfp_EELb1E", "auto void test7::f()::'lambda0' requires C && C (auto)::operator()(auto) const requires C && true"}, + {"_ZZN5test71fIiEEvvENKUlTyQaa1CIT_E1CITL0__ET0_E1_clIiiEEDaS3_Q1CIDtfp_EE", "auto void test7::f()::'lambda1' requires C && C (auto)::operator()(auto) const requires C"}, + {"_ZZN5test71fIiEEvvENKUlTyT0_E_clIiiEEDaS1_", "auto void test7::f()::'lambda'(auto)::operator()(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) requires requires { (T)(); fp; fp == (T)(); {(T)() + 1} -> Small; {(T)() - 1} noexcept; {(T)() * 2} noexcept -> SmallerThan<1234>; typename T; typename X; typename X::type; typename X; requires SmallerThan; }"}, + {"_Z1gIiEviQrQT__XplfL0p_fp_E", "void g(int) requires requires (T) { fp + fp; }"}, + // Special Substs a, b, d, i, o, s (not including std::) {"_Z1fSaIiE", "f(std::allocator)"}, {"_Z1fSbIiE", "f(std::basic_string)"}, diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index 04faeb462e097..fde2085e26089 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 #include #include @@ -31,6 +32,11 @@ #include #include +#ifdef _LIBCXXABI_COMPILER_CLANG +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-template" +#endif + DEMANGLE_NAMESPACE_BEGIN template class PODSmallVector { @@ -127,8 +133,8 @@ template 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 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 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 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 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 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 void match(Fn F) const { F(Name, Params); } + template void match(Fn F) const { F(Name, Params, Requires); } void printLeft(OutputBuffer &OB) const override { ScopedOverride 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 /// JE in some . 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 this pack belongs to apply to an /// . 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 void match(Fn F) const { F(Params); } + template 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 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 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 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 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 void match(Fn F) const { F(Constraint); } + + void printLeft(OutputBuffer &OB) const override { + OB += " requires "; + Constraint->print(OB); + OB += ';'; + } +}; + template struct FloatData; namespace float_literal_impl { @@ -2397,6 +2578,8 @@ template struct AbstractManglingParser { // table. PODSmallVector Subs; + // A list of template argument values corresponding to a template parameter + // list. using TemplateParamList = PODSmallVector; class ScopedTemplateParamList { @@ -2412,8 +2595,9 @@ template 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 struct AbstractManglingParser { // parameter list, the corresponding parameter list pointer will be null. PODSmallVector 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 references. These can occur in a // conversion operator's type, and are resolved in the enclosing . PODSmallVector ForwardTemplateRefs; bool TryToParseTemplateArgs = true; bool PermitForwardTemplateReferences = false; + bool InConstraintExpr = false; size_t ParsingLambdaParamsAtLevel = (size_t)-1; unsigned NumSyntheticTemplateParameters[3] = {}; @@ -2475,13 +2678,12 @@ template 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 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 production. + bool isTemplateParamDecl() { + return look() == 'T' && + std::string_view("yptnk").find(look(1)) != std::string_view::npos; + } + + /// Parse the 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 struct AbstractManglingParser { Node *parseFoldExpr(); Node *parsePointerToMemberConversionExpr(Node::Prec Prec); Node *parseSubobjectExpr(); + Node *parseConstraintExpr(); + Node *parseRequiresExpr(); /// Parse the production. Node *parseType(); @@ -2569,7 +2778,7 @@ template 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 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::parseLocalName(NameState *State) { return make(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::parseUnscopedName(NameState *State, return Res; } -// ::= [] L? [] +// ::= [] F? L? [] // ::= [] [] -// ::= [] L? [] +// ::= [] F? L? [] // ::= [] L? [] // # structured binding declaration // ::= [] L? DC + E @@ -2789,6 +3002,8 @@ Node *AbstractManglingParser::parseUnqualifiedName( if (getDerived().parseModuleNameOpt(Module)) return nullptr; + bool IsMemberLikeFriend = Scope && consumeIf('F'); + consumeIf('L'); Node *Result; @@ -2819,7 +3034,9 @@ Node *AbstractManglingParser::parseUnqualifiedName( Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); - if (Result != nullptr && Scope != nullptr) + if (Result != nullptr && IsMemberLikeFriend) + Result = make(Scope, Result); + else if (Result != nullptr && Scope != nullptr) Result = make(Scope, Result); return Result; @@ -2851,7 +3068,8 @@ bool AbstractManglingParser::parseModuleNameOpt( // // ::= Ul E [ ] _ // -// ::= + # Parameter types or "v" if the lambda has no parameters +// ::= * [Q ] +// + # or "v" if the lambda has no parameters template Node * AbstractManglingParser::parseUnnamedTypeName(NameState *State) { @@ -2872,10 +3090,10 @@ AbstractManglingParser::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::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(TempParams, Params, Count); + return make(TempParams, Requires1, Params, Requires2, + Count); } if (consumeIf("Ub")) { (void)parseNumber(); @@ -2940,7 +3176,7 @@ Node *AbstractManglingParser::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("(anonymous namespace)"); return make(Name); } @@ -3709,7 +3945,7 @@ Node *AbstractManglingParser::parseQualifiedType() { return nullptr; // extension ::= U # objc-type - 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::parseType() { case 'c': First += 2; return make("decltype(auto)"); + // ::= Dk # constrained auto + // ::= DK # 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(Constraint, Kind); + } // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) case 'n': First += 2; @@ -4507,6 +4754,75 @@ Node *AbstractManglingParser::parseSubobjectExpr() { Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); } +template +Node *AbstractManglingParser::parseConstraintExpr() { + // Within this expression, all enclosing template parameter lists are in + // scope. + ScopedOverride SaveInConstraintExpr(InConstraintExpr, true); + return getDerived().parseExpr(); +} + +template +Node *AbstractManglingParser::parseRequiresExpr() { + NodeArray Params; + if (consumeIf("rQ")) { + // ::= rQ _ + 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")) { + // ::= rq + E + return nullptr; + } + + size_t ReqsBegin = Names.size(); + do { + Node *Constraint = nullptr; + if (consumeIf('X')) { + // ::= X [N] [R ] + 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(Expr, Noexcept, TypeReq); + } else if (consumeIf('T')) { + // ::= T + Node *Type = getDerived().parseType(); + if (Type == nullptr) + return nullptr; + Constraint = make(Type); + } else if (consumeIf('Q')) { + // ::= Q + // + // FIXME: We use instead of . Either + // the requires expression is already inside a constraint expression, in + // which case it makes no difference, 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(NestedReq); + } + if (Constraint == nullptr) + return nullptr; + Names.push_back(Constraint); + } while (!consumeIf('E')); + + return make(Params, popTrailingNodeArray(ReqsBegin)); +} + // ::= // ::= // ::= @@ -4743,6 +5059,8 @@ Node *AbstractManglingParser::parseExpr() { return Ex; return make("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::parseSpecialName() { } // ::= +// [`Q` ] // ::= // ::= template Node *AbstractManglingParser::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::parseEncoding() { return nullptr; } - if (consumeIf('v')) - return make(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(ReturnType, Name, - popTrailingNodeArray(ParamsBegin), - Attrs, NameInfo.CVQualifiers, + return make(ReturnType, Name, Params, Attrs, Requires, + NameInfo.CVQualifiers, NameInfo.ReferenceQualifier); } @@ -5264,6 +5572,7 @@ Node *AbstractManglingParser::parseSubstitution() { // ::= TL _ _ template Node *AbstractManglingParser::parseTemplateParam() { + const char *Begin = First; if (!consumeIf('T')) return nullptr; @@ -5285,6 +5594,14 @@ Node *AbstractManglingParser::parseTemplateParam() { return nullptr; } + // We don't track enclosing template parameter levels well enough to reliably + // substitute them all within a , so print the + // parameter numbering instead for now. + // TODO: Track all enclosing template parameters and substitute them here. + if (InConstraintExpr) { + return make(std::string_view(Begin, First - 1 - Begin)); + } + // If we're in a context where this refers to a // 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::parseTemplateParam() { // ::= Tt * E # template parameter // ::= Tp # parameter pack template -Node *AbstractManglingParser::parseTemplateParamDecl() { +Node *AbstractManglingParser::parseTemplateParamDecl( + TemplateParamList *Params) { auto InventTemplateParamName = [&](TemplateParamKind Kind) { unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++; Node *N = make(Kind, Index); - if (N) TemplateParams.back()->push_back(N); + if (N && Params) + Params->push_back(N); return N; }; @@ -5337,6 +5656,16 @@ Node *AbstractManglingParser::parseTemplateParamDecl() { return make(Name); } + if (consumeIf("Tk")) { + Node *Constraint = getDerived().parseName(); + if (!Constraint) + return nullptr; + Node *Name = InventTemplateParamName(TemplateParamKind::Type); + if (!Name) + return nullptr; + return make(Constraint, Name); + } + if (consumeIf("Tn")) { Node *Name = InventTemplateParamName(TemplateParamKind::NonType); if (!Name) @@ -5353,18 +5682,25 @@ Node *AbstractManglingParser::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(Name, Params); + NodeArray InnerParams = popTrailingNodeArray(ParamsBegin); + return make(Name, InnerParams, Requires); } if (consumeIf("Tp")) { - Node *P = parseTemplateParamDecl(); + Node *P = parseTemplateParamDecl(Params); if (!P) return nullptr; return make(P); @@ -5378,6 +5714,7 @@ Node *AbstractManglingParser::parseTemplateParamDecl() { // ::= # simple expressions // ::= J * E # argument pack // ::= LZ E # extension +// ::= template Node *AbstractManglingParser::parseTemplateArg() { switch (look()) { @@ -5412,6 +5749,18 @@ Node *AbstractManglingParser::parseTemplateArg() { // ::= # simple expressions return getDerived().parseExprPrimary(); } + case 'T': { + // Either or a . + 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(Param, Arg); + } default: return getDerived().parseType(); } @@ -5434,30 +5783,39 @@ AbstractManglingParser::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(TableEntry)->getArg(); + } if (Arg->getKind() == Node::KTemplateArgumentPack) { TableEntry = make( static_cast(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(popTrailingNodeArray(ArgsBegin)); + return make(popTrailingNodeArray(ArgsBegin), Requires); } // ::= _Z @@ -5509,4 +5867,8 @@ struct ManglingParser : AbstractManglingParser, 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 c0e277d554ccf..12cfa70f93e63 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