diff options
author | Richard Smith <richard@metafoo.co.uk> | 2023-09-12 18:53:54 -0700 |
---|---|---|
committer | Richard Smith <richard@metafoo.co.uk> | 2023-09-20 12:38:15 -0700 |
commit | 4b163e343cfa54c8d55c9da73c70d58f55ea9df2 (patch) | |
tree | f7a4a25c0d82dba24434851d5731d5e6f0579c7a /clang/lib | |
parent | 5d95d27e50c1f5ce4803039d942ff3c25401c77f (diff) | |
download | llvm-4b163e343cfa54c8d55c9da73c70d58f55ea9df2.zip llvm-4b163e343cfa54c8d55c9da73c70d58f55ea9df2.tar.gz llvm-4b163e343cfa54c8d55c9da73c70d58f55ea9df2.tar.bz2 |
Implement mangling rules for C++20 concepts and requires-expressions.
This implements proposals from:
- https://github.com/itanium-cxx-abi/cxx-abi/issues/24: mangling for
constraints, requires-clauses, requires-expressions.
- https://github.com/itanium-cxx-abi/cxx-abi/issues/31: requires-clauses and
template parameters in a lambda expression are mangled into the <lambda-sig>.
- https://github.com/itanium-cxx-abi/cxx-abi/issues/47 (STEP 3): mangling for
template argument is prefixed by mangling of template parameter declaration
if it's not "obvious", for example because the template parameter is
constrained (we already implemented STEP 1 and STEP 2).
This changes the manglings for a few cases:
- Functions and function templates with constraints.
- Function templates with template parameters with deduced types:
`typename<auto N> void f();`
- Function templates with template template parameters where the argument has a
different template-head:
`template<template<typename...T>> void f(); f<std::vector>();`
In each case where a mangling changed, the change fixes a mangling collision.
Note that only function templates are affected, not class templates or variable
templates, and only new constructs (template parameters with deduced types,
constrained templates) and esoteric constructs (templates with template
template parameters with non-matching template template arguments, most of
which Clang still does not accept by default due to
`-frelaxed-template-template-args` not being enabled by default), so the risk
to ABI stability from this change is relatively low. Nonetheless,
`-fclang-abi-compat=17` can be used to restore the old manglings for cases
which we could successfully but incorrectly mangle before.
Fixes #48216, #49884, #61273
Reviewed By: erichkeane, #libc_abi
Differential Revision: https://reviews.llvm.org/D147655
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ExprConcepts.cpp | 22 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 534 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 16 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderStmt.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterStmt.cpp | 2 |
9 files changed, 494 insertions, 146 deletions
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index 2aa1504..0704630 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -117,13 +117,15 @@ static bool RequirementContainsError(concepts::Requirement *R) { } RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, - RequiresExprBodyDecl *Body, + RequiresExprBodyDecl *Body, SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters, + SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements, SourceLocation RBraceLoc) : Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary), NumLocalParameters(LocalParameters.size()), - NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) { + NumRequirements(Requirements.size()), Body(Body), LParenLoc(LParenLoc), + RParenLoc(RParenLoc), RBraceLoc(RBraceLoc) { RequiresExprBits.IsSatisfied = false; RequiresExprBits.RequiresKWLoc = RequiresKWLoc; bool Dependent = false; @@ -168,18 +170,18 @@ RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty, : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters), NumRequirements(NumRequirements) { } -RequiresExpr * -RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc, - RequiresExprBodyDecl *Body, - ArrayRef<ParmVarDecl *> LocalParameters, - ArrayRef<concepts::Requirement *> Requirements, - SourceLocation RBraceLoc) { +RequiresExpr *RequiresExpr::Create( + ASTContext &C, SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, + SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters, + SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements, + SourceLocation RBraceLoc) { void *Mem = C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( LocalParameters.size(), Requirements.size()), alignof(RequiresExpr)); - return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters, - Requirements, RBraceLoc); + return new (Mem) + RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters, + RParenLoc, Requirements, RBraceLoc); } RequiresExpr * diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 53963d2..3bbc0a5 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 @@ public: 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 @@ private: void mangleBlockForPrefix(const BlockDecl *Block); void mangleUnqualifiedBlock(const BlockDecl *Block); void mangleTemplateParamDecl(const NamedDecl *Decl); + void mangleTemplateParameterList(const TemplateParameterList *Params); + void mangleTypeConstraint(const ConceptDecl *Concept, + ArrayRef<TemplateArgument> Arguments); + void mangleTypeConstraint(const TypeConstraint *Constraint); + void mangleRequiresClause(const Expr *RequiresClause); void mangleLambda(const CXXRecordDecl *Lambda); void mangleNestedName(GlobalDecl GD, const DeclContext *DC, const AbiTagList *AdditionalAbiTags, @@ -580,16 +601,21 @@ private: unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); + void mangleRequirement(SourceLocation RequiresExprLoc, + const concepts::Requirement *Req); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity, bool AsTemplateArg = false); void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom); void mangleCXXDtorType(CXXDtorType T); + struct TemplateArgManglingInfo; void mangleTemplateArgs(TemplateName TN, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs); void mangleTemplateArgs(TemplateName TN, ArrayRef<TemplateArgument> Args); void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL); + void mangleTemplateArg(TemplateArgManglingInfo &Info, unsigned Index, + TemplateArgument A); void mangleTemplateArg(TemplateArgument A, bool NeedExactType); void mangleTemplateArgExpr(const Expr *E); void mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel, @@ -667,9 +693,16 @@ ItaniumMangleContextImpl::getEffectiveDeclContext(const Decl *D) { if (VD->isExternC()) return getASTContext().getTranslationUnitDecl(); - if (const auto *FD = dyn_cast<FunctionDecl>(D)) + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isExternC()) return getASTContext().getTranslationUnitDecl(); + // Member-like constrained friends are mangled as if they were members of + // the enclosing class. + if (FD->isMemberLikeConstrainedFriend() && + getASTContext().getLangOpts().getClangABICompat() > + LangOptions::ClangABI::Ver17) + return D->getLexicalDeclContext()->getRedeclContext(); + } return DC->getRedeclContext(); } @@ -858,16 +891,15 @@ void CXXNameMangler::mangleFunctionEncodingBareType(const FunctionDecl *FD) { EnableIfAttr *EIA = dyn_cast<EnableIfAttr>(*I); if (!EIA) continue; - if (Context.getASTContext().getLangOpts().getClangABICompat() > - LangOptions::ClangABI::Ver11) { - mangleTemplateArgExpr(EIA->getCond()); - } else { + if (isCompatibleWith(LangOptions::ClangABI::Ver11)) { // Prior to Clang 12, we hardcoded the X/E around enable-if's argument, // even though <template-arg> should not include an X/E around // <expr-primary>. Out << 'X'; mangleExpression(EIA->getCond()); Out << 'E'; + } else { + mangleTemplateArgExpr(EIA->getCond()); } } Out << 'E'; @@ -1415,14 +1447,24 @@ void CXXNameMangler::mangleUnqualifiedName( GlobalDecl GD, DeclarationName Name, const DeclContext *DC, unsigned KnownArity, const AbiTagList *AdditionalAbiTags) { const NamedDecl *ND = cast_or_null<NamedDecl>(GD.getDecl()); - // <unqualified-name> ::= [<module-name>] <operator-name> + // <unqualified-name> ::= [<module-name>] [F] <operator-name> // ::= <ctor-dtor-name> - // ::= [<module-name>] <source-name> + // ::= [<module-name>] [F] <source-name> // ::= [<module-name>] DC <source-name>* E if (ND && DC && DC->isFileContext()) mangleModuleName(ND); + // A member-like constrained friend is mangled with a leading 'F'. + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24. + auto *FD = dyn_cast<FunctionDecl>(ND); + auto *FTD = dyn_cast<FunctionTemplateDecl>(ND); + if ((FD && FD->isMemberLikeConstrainedFriend()) || + (FTD && FTD->getTemplatedDecl()->isMemberLikeConstrainedFriend())) { + if (!isCompatibleWith(LangOptions::ClangABI::Ver17)) + Out << 'F'; + } + unsigned Arity = KnownArity; switch (Name.getNameKind()) { case DeclarationName::Identifier: { @@ -1478,7 +1520,6 @@ void CXXNameMangler::mangleUnqualifiedName( if (Context.isInternalLinkageDecl(ND)) Out << 'L'; - auto *FD = dyn_cast<FunctionDecl>(ND); bool IsRegCall = FD && FD->getType()->castAs<FunctionType>()->getCallConv() == clang::CC_X86RegCall; @@ -1911,8 +1952,7 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) { // When trying to be ABI-compatibility with clang 12 and before, mangle a // <data-member-prefix> now, with no substitutions and no <template-args>. if (Decl *Context = Block->getBlockManglingContextDecl()) { - if (getASTContext().getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver12 && + if (isCompatibleWith(LangOptions::ClangABI::Ver12) && (isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && Context->getDeclContext()->isRecord()) { const auto *ND = cast<NamedDecl>(Context); @@ -1940,15 +1980,25 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) { } // <template-param-decl> -// ::= Ty # template type parameter -// ::= Tn <type> # template non-type parameter -// ::= Tt <template-param-decl>* E # template template parameter -// ::= Tp <template-param-decl> # template parameter pack +// ::= Ty # template type parameter +// ::= Tk <concept name> [<template-args>] # constrained type parameter +// ::= Tn <type> # template non-type parameter +// ::= Tt <template-param-decl>* E [Q <requires-clause expr>] +// # template template parameter +// ::= Tp <template-param-decl> # template parameter pack void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/47. if (auto *Ty = dyn_cast<TemplateTypeParmDecl>(Decl)) { if (Ty->isParameterPack()) Out << "Tp"; - Out << "Ty"; + const TypeConstraint *Constraint = Ty->getTypeConstraint(); + if (Constraint && !isCompatibleWith(LangOptions::ClangABI::Ver17)) { + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24. + Out << "Tk"; + mangleTypeConstraint(Constraint); + } else { + Out << "Ty"; + } } else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) { if (Tn->isExpandedParameterPack()) { for (unsigned I = 0, N = Tn->getNumExpansionTypes(); I != N; ++I) { @@ -1968,29 +2018,59 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { } else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) { if (Tt->isExpandedParameterPack()) { for (unsigned I = 0, N = Tt->getNumExpansionTemplateParameters(); I != N; - ++I) { - Out << "Tt"; - for (auto *Param : *Tt->getExpansionTemplateParameters(I)) - mangleTemplateParamDecl(Param); - Out << "E"; - } + ++I) + mangleTemplateParameterList(Tt->getExpansionTemplateParameters(I)); } else { if (Tt->isParameterPack()) Out << "Tp"; - Out << "Tt"; - for (auto *Param : *Tt->getTemplateParameters()) - mangleTemplateParamDecl(Param); - Out << "E"; + mangleTemplateParameterList(Tt->getTemplateParameters()); } } } +void CXXNameMangler::mangleTemplateParameterList( + const TemplateParameterList *Params) { + Out << "Tt"; + for (auto *Param : *Params) + mangleTemplateParamDecl(Param); + mangleRequiresClause(Params->getRequiresClause()); + Out << "E"; +} + +void CXXNameMangler::mangleTypeConstraint( + const ConceptDecl *Concept, ArrayRef<TemplateArgument> Arguments) { + const DeclContext *DC = Context.getEffectiveDeclContext(Concept); + if (!Arguments.empty()) + mangleTemplateName(Concept, Arguments); + else if (DC->isTranslationUnit() || isStdNamespace(DC)) + mangleUnscopedName(Concept, DC, nullptr); + else + mangleNestedName(Concept, DC, nullptr); +} + +void CXXNameMangler::mangleTypeConstraint(const TypeConstraint *Constraint) { + llvm::SmallVector<TemplateArgument, 8> Args; + if (Constraint->getTemplateArgsAsWritten()) { + for (const TemplateArgumentLoc &ArgLoc : + Constraint->getTemplateArgsAsWritten()->arguments()) + Args.push_back(ArgLoc.getArgument()); + } + return mangleTypeConstraint(Constraint->getNamedConcept(), Args); +} + +void CXXNameMangler::mangleRequiresClause(const Expr *RequiresClause) { + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24. + if (RequiresClause && !isCompatibleWith(LangOptions::ClangABI::Ver17)) { + Out << 'Q'; + mangleExpression(RequiresClause); + } +} + void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // When trying to be ABI-compatibility with clang 12 and before, mangle a // <data-member-prefix> now, with no substitutions. if (Decl *Context = Lambda->getLambdaContextDecl()) { - if (getASTContext().getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver12 && + if (isCompatibleWith(LangOptions::ClangABI::Ver12) && (isa<VarDecl>(Context) || isa<FieldDecl>(Context)) && !isa<ParmVarDecl>(Context)) { if (const IdentifierInfo *Name @@ -2031,8 +2111,14 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { } void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) { + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/31. for (auto *D : Lambda->getLambdaExplicitTemplateParameters()) mangleTemplateParamDecl(D); + + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24. + if (auto *TPL = Lambda->getGenericLambdaTemplateParameterList()) + mangleRequiresClause(TPL->getRequiresClause()); + auto *Proto = Lambda->getLambdaTypeInfo()->getType()->castAs<FunctionProtoType>(); mangleBareFunctionType(Proto, /*MangleReturnType=*/false, @@ -2063,8 +2149,7 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { case NestedNameSpecifier::Identifier: // Clang 14 and before did not consider this substitutable. - bool Clang14Compat = getASTContext().getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver14; + bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14); if (!Clang14Compat && mangleSubstitution(qualifier)) return; @@ -2134,8 +2219,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { // Clang 11 and before mangled the substitution for a dependent template name // after already having emitted (a substitution for) the prefix. - bool Clang11Compat = getASTContext().getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver11; + bool Clang11Compat = isCompatibleWith(LangOptions::ClangABI::Ver11); if (!Clang11Compat && mangleSubstitution(Template)) return; @@ -2182,8 +2266,7 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD, } const NamedDecl *CXXNameMangler::getClosurePrefix(const Decl *ND) { - if (getASTContext().getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver12) + if (isCompatibleWith(LangOptions::ClangABI::Ver12)) return nullptr; const NamedDecl *Context = nullptr; @@ -3430,39 +3513,42 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionProtoType *Proto, if (Proto->getNumParams() == 0 && !Proto->isVariadic()) { // <builtin-type> ::= v # void Out << 'v'; + } else { + assert(!FD || FD->getNumParams() == Proto->getNumParams()); + for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) { + // Mangle extended parameter info as order-sensitive qualifiers here. + if (Proto->hasExtParameterInfos() && FD == nullptr) { + mangleExtParameterInfo(Proto->getExtParameterInfo(I)); + } - FunctionTypeDepth.pop(saved); - return; - } - - assert(!FD || FD->getNumParams() == Proto->getNumParams()); - for (unsigned I = 0, E = Proto->getNumParams(); I != E; ++I) { - // Mangle extended parameter info as order-sensitive qualifiers here. - if (Proto->hasExtParameterInfos() && FD == nullptr) { - mangleExtParameterInfo(Proto->getExtParameterInfo(I)); + // Mangle the type. + QualType ParamTy = Proto->getParamType(I); + mangleType(Context.getASTContext().getSignatureParameterType(ParamTy)); + + if (FD) { + if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) { + // Attr can only take 1 character, so we can hardcode the length + // below. + assert(Attr->getType() <= 9 && Attr->getType() >= 0); + if (Attr->isDynamic()) + Out << "U25pass_dynamic_object_size" << Attr->getType(); + else + Out << "U17pass_object_size" << Attr->getType(); + } + } } - // Mangle the type. - QualType ParamTy = Proto->getParamType(I); - mangleType(Context.getASTContext().getSignatureParameterType(ParamTy)); + // <builtin-type> ::= z # ellipsis + if (Proto->isVariadic()) + Out << 'z'; + } - if (FD) { - if (auto *Attr = FD->getParamDecl(I)->getAttr<PassObjectSizeAttr>()) { - // Attr can only take 1 character, so we can hardcode the length below. - assert(Attr->getType() <= 9 && Attr->getType() >= 0); - if (Attr->isDynamic()) - Out << "U25pass_dynamic_object_size" << Attr->getType(); - else - Out << "U17pass_object_size" << Attr->getType(); - } - } + if (FD) { + FunctionTypeDepth.enterResultType(); + mangleRequiresClause(FD->getTrailingRequiresClause()); } FunctionTypeDepth.pop(saved); - - // <builtin-type> ::= z # ellipsis - if (Proto->isVariadic()) - Out << 'z'; } // <type> ::= <class-enum-type> @@ -4198,7 +4284,15 @@ void CXXNameMangler::mangleType(const AutoType *T) { "shouldn't need to mangle __auto_type!"); // <builtin-type> ::= Da # auto // ::= Dc # decltype(auto) - Out << (T->isDecltypeAuto() ? "Dc" : "Da"); + // ::= Dk # constrained auto + // ::= DK # constrained decltype(auto) + if (T->isConstrained() && !isCompatibleWith(LangOptions::ClangABI::Ver17)) { + Out << (T->isDecltypeAuto() ? "DK" : "Dk"); + mangleTypeConstraint(T->getTypeConstraintConcept(), + T->getTypeConstraintArguments()); + } else { + Out << (T->isDecltypeAuto() ? "Dc" : "Da"); + } } void CXXNameMangler::mangleType(const DeducedTemplateSpecializationType *T) { @@ -4346,6 +4440,74 @@ void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) { mangleExpression(InitList->getInit(i)); } +void CXXNameMangler::mangleRequirement(SourceLocation RequiresExprLoc, + const concepts::Requirement *Req) { + using concepts::Requirement; + + // TODO: We can't mangle the result of a failed substitution. It's not clear + // whether we should be mangling the original form prior to any substitution + // instead. See https://lists.isocpp.org/core/2023/04/14118.php + auto HandleSubstitutionFailure = + [&](SourceLocation Loc) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID( + DiagnosticsEngine::Error, "cannot mangle this requires-expression " + "containing a substitution failure"); + Diags.Report(Loc, DiagID); + Out << 'F'; + }; + + switch (Req->getKind()) { + case Requirement::RK_Type: { + const auto *TR = cast<concepts::TypeRequirement>(Req); + if (TR->isSubstitutionFailure()) + return HandleSubstitutionFailure( + TR->getSubstitutionDiagnostic()->DiagLoc); + + Out << 'T'; + mangleType(TR->getType()->getType()); + break; + } + + case Requirement::RK_Simple: + case Requirement::RK_Compound: { + const auto *ER = cast<concepts::ExprRequirement>(Req); + if (ER->isExprSubstitutionFailure()) + return HandleSubstitutionFailure( + ER->getExprSubstitutionDiagnostic()->DiagLoc); + + Out << 'X'; + mangleExpression(ER->getExpr()); + + if (ER->hasNoexceptRequirement()) + Out << 'N'; + + if (!ER->getReturnTypeRequirement().isEmpty()) { + if (ER->getReturnTypeRequirement().isSubstitutionFailure()) + return HandleSubstitutionFailure(ER->getReturnTypeRequirement() + .getSubstitutionDiagnostic() + ->DiagLoc); + + Out << 'R'; + mangleTypeConstraint(ER->getReturnTypeRequirement().getTypeConstraint()); + } + break; + } + + case Requirement::RK_Nested: + const auto *NR = cast<concepts::NestedRequirement>(Req); + if (NR->hasInvalidConstraint()) { + // FIXME: NestedRequirement should track the location of its requires + // keyword. + return HandleSubstitutionFailure(RequiresExprLoc); + } + + Out << 'Q'; + mangleExpression(NR->getConstraintExpr()); + break; + } +} + void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, bool AsTemplateArg) { // <expression> ::= <unary operator-name> <expression> @@ -4479,7 +4641,6 @@ recurse: 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 @@ recurse: const CXXUuidofExpr *UE = cast<CXXUuidofExpr>(E); // As of clang 12, uuidof uses the vendor extended expression // mangling. Previously, it used a special-cased nonstandard extension. - if (Context.getASTContext().getLangOpts().getClangABICompat() > - LangOptions::ClangABI::Ver11) { + if (!isCompatibleWith(LangOptions::ClangABI::Ver11)) { Out << "u8__uuidof"; if (UE->isTypeOperand()) mangleType(UE->getTypeOperand(Context.getASTContext())); @@ -4861,8 +5021,7 @@ recurse: // 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 @@ recurse: goto recurse; case Expr::ConceptSpecializationExprClass: { - // <expr-primary> ::= L <mangled-name> E # external name - Out << "L_Z"; auto *CSE = cast<ConceptSpecializationExpr>(E); - mangleTemplateName(CSE->getNamedConcept(), CSE->getTemplateArguments()); - Out << 'E'; + if (isCompatibleWith(LangOptions::ClangABI::Ver17)) { + // Clang 17 and before mangled concept-ids as if they resolved to an + // entity, meaning that references to enclosing template arguments don't + // work. + Out << "L_Z"; + mangleTemplateName(CSE->getNamedConcept(), CSE->getTemplateArguments()); + Out << 'E'; + break; + } + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24. + NotPrimaryExpr(); + mangleUnresolvedName( + CSE->getNestedNameSpecifierLoc().getNestedNameSpecifier(), + CSE->getConceptNameInfo().getName(), + CSE->getTemplateArgsAsWritten()->getTemplateArgs(), + CSE->getTemplateArgsAsWritten()->getNumTemplateArgs()); + break; + } + + case Expr::RequiresExprClass: { + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/24. + auto *RE = cast<RequiresExpr>(E); + // This is a primary-expression in the C++ grammar, but does not have an + // <expr-primary> mangling (starting with 'L'). + NotPrimaryExpr(); + if (RE->getLParenLoc().isValid()) { + Out << "rQ"; + FunctionTypeDepthState saved = FunctionTypeDepth.push(); + if (RE->getLocalParameters().empty()) { + Out << 'v'; + } else { + for (ParmVarDecl *Param : RE->getLocalParameters()) { + mangleType(Context.getASTContext().getSignatureParameterType( + Param->getType())); + } + } + Out << '_'; + + // The rest of the mangling is in the immediate scope of the parameters. + FunctionTypeDepth.enterResultType(); + for (const concepts::Requirement *Req : RE->getRequirements()) + mangleRequirement(RE->getExprLoc(), Req); + FunctionTypeDepth.pop(saved); + Out << 'E'; + } else { + Out << "rq"; + for (const concepts::Requirement *Req : RE->getRequirements()) + mangleRequirement(RE->getExprLoc(), Req); + Out << 'E'; + } break; } @@ -5448,28 +5653,116 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { } } -namespace { // Helper to provide ancillary information on a template used to mangle its // arguments. -struct TemplateArgManglingInfo { +struct CXXNameMangler::TemplateArgManglingInfo { + const CXXNameMangler &Mangler; TemplateDecl *ResolvedTemplate = nullptr; bool SeenPackExpansionIntoNonPack = false; const NamedDecl *UnresolvedExpandedPack = nullptr; - TemplateArgManglingInfo(TemplateName TN) { + TemplateArgManglingInfo(const CXXNameMangler &Mangler, TemplateName TN) + : Mangler(Mangler) { if (TemplateDecl *TD = TN.getAsTemplateDecl()) ResolvedTemplate = TD; } - /// Do we need to mangle template arguments with exactly correct types? - /// + /// Information about how to mangle a template argument. + struct Info { + /// Do we need to mangle the template argument with an exactly correct type? + bool NeedExactType; + /// If we need to prefix the mangling with a mangling of the template + /// parameter, the corresponding parameter. + const NamedDecl *TemplateParameterToMangle; + }; + + /// Determine whether the resolved template might be overloaded on its + /// template parameter list. If so, the mangling needs to include enough + /// information to reconstruct the template parameter list. + bool isOverloadable() { + // Function templates are generally overloadable. As a special case, a + // member function template of a generic lambda is not overloadable. + if (auto *FTD = dyn_cast_or_null<FunctionTemplateDecl>(ResolvedTemplate)) { + auto *RD = dyn_cast<CXXRecordDecl>(FTD->getDeclContext()); + if (!RD || !RD->isGenericLambda()) + return true; + } + + // All other templates are not overloadable. Partial specializations would + // be, but we never mangle them. + return false; + } + + /// Determine whether we need to prefix this <template-arg> mangling with a + /// <template-param-decl>. This happens if the natural template parameter for + /// the argument mangling is not the same as the actual template parameter. + bool needToMangleTemplateParam(const NamedDecl *Param, + const TemplateArgument &Arg) { + // For a template type parameter, the natural parameter is 'typename T'. + // The actual parameter might be constrained. + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + return TTP->hasTypeConstraint(); + + if (Arg.getKind() == TemplateArgument::Pack) { + // For an empty pack, the natural parameter is `typename...`. + if (Arg.pack_size() == 0) + return true; + + // For any other pack, we use the first argument to determine the natural + // template parameter. + return needToMangleTemplateParam(Param, *Arg.pack_begin()); + } + + // For a non-type template parameter, the natural parameter is `T V` (for a + // prvalue argument) or `T &V` (for a glvalue argument), where `T` is the + // type of the argument, which we require to exactly match. If the actual + // parameter has a deduced or instantiation-dependent type, it is not + // equivalent to the natural parameter. + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) + return NTTP->getType()->isInstantiationDependentType() || + NTTP->getType()->getContainedDeducedType(); + + // For a template template parameter, the template-head might differ from + // that of the template. + auto *TTP = cast<TemplateTemplateParmDecl>(Param); + TemplateName ArgTemplateName = Arg.getAsTemplateOrTemplatePattern(); + const TemplateDecl *ArgTemplate = ArgTemplateName.getAsTemplateDecl(); + if (!ArgTemplate) + return true; + + // Mangle the template parameter list of the parameter and argument to see + // if they are the same. We can't use Profile for this, because it can't + // model the depth 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<char> &Buffer, const TemplateParameterList *Params, + unsigned DepthOffset) { + llvm::raw_svector_ostream Stream(Buffer); + CXXNameMangler(Mangler.Context, Stream, + WithTemplateDepthOffset{DepthOffset}) + .mangleTemplateParameterList(Params); + }; + llvm::SmallString<128> ParamTemplateHead, ArgTemplateHead; + MangleTemplateParamListToString(ParamTemplateHead, + TTP->getTemplateParameters(), 0); + // Add the depth of the parameter's template parameter list to all + // parameters appearing in the argument to make the indexes line up + // properly. + MangleTemplateParamListToString(ArgTemplateHead, + ArgTemplate->getTemplateParameters(), + TTP->getTemplateParameters()->getDepth()); + return ParamTemplateHead != ArgTemplateHead; + } + + /// Determine information about how this template argument should be mangled. /// This should be called exactly once for each parameter / argument pair, in /// order. - bool needExactType(unsigned ParamIdx, const TemplateArgument &Arg) { + Info getArgInfo(unsigned ParamIdx, const TemplateArgument &Arg) { // We need correct types when the template-name is unresolved or when it // names a template that is able to be overloaded. if (!ResolvedTemplate || SeenPackExpansionIntoNonPack) - return true; + return {true, nullptr}; // Move to the next parameter. const NamedDecl *Param = UnresolvedExpandedPack; @@ -5495,17 +5788,13 @@ struct TemplateArgManglingInfo { if (Arg.isPackExpansion() && (!Param->isParameterPack() || UnresolvedExpandedPack)) { SeenPackExpansionIntoNonPack = true; - return true; + return {true, nullptr}; } - // We need exact types for function template arguments because they might be - // overloaded on template parameter type. As a special case, a member - // function template of a generic lambda is not overloadable. - if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ResolvedTemplate)) { - auto *RD = dyn_cast<CXXRecordDecl>(FTD->getDeclContext()); - if (!RD || !RD->isGenericLambda()) - return true; - } + // We need exact types for arguments of a template that might be overloaded + // on template parameter type. + if (isOverloadable()) + return {true, needToMangleTemplateParam(Param, Arg) ? Param : nullptr}; // Otherwise, we only need a correct type if the parameter has a deduced // type. @@ -5515,43 +5804,75 @@ struct TemplateArgManglingInfo { // but it doesn't matter because substitution and expansion don't affect // whether a deduced type appears in the type. auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param); - return NTTP && NTTP->getType()->getContainedDeducedType(); + bool NeedExactType = NTTP && NTTP->getType()->getContainedDeducedType(); + return {NeedExactType, nullptr}; + } + + /// Determine if we should mangle a requires-clause after the template + /// argument list. If so, returns the expression to mangle. + const Expr *getTrailingRequiresClauseToMangle() { + if (!isOverloadable()) + return nullptr; + return ResolvedTemplate->getTemplateParameters()->getRequiresClause(); } }; -} void CXXNameMangler::mangleTemplateArgs(TemplateName TN, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs) { - // <template-args> ::= I <template-arg>+ E + // <template-args> ::= I <template-arg>+ [Q <requires-clause expr>] E Out << 'I'; - TemplateArgManglingInfo Info(TN); - for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(TemplateArgs[i].getArgument(), - Info.needExactType(i, TemplateArgs[i].getArgument())); + TemplateArgManglingInfo Info(*this, TN); + for (unsigned i = 0; i != NumTemplateArgs; ++i) { + mangleTemplateArg(Info, i, TemplateArgs[i].getArgument()); + } + mangleRequiresClause(Info.getTrailingRequiresClauseToMangle()); Out << 'E'; } void CXXNameMangler::mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL) { - // <template-args> ::= I <template-arg>+ E + // <template-args> ::= I <template-arg>+ [Q <requires-clause expr>] E Out << 'I'; - TemplateArgManglingInfo Info(TN); - for (unsigned i = 0, e = AL.size(); i != e; ++i) - mangleTemplateArg(AL[i], Info.needExactType(i, AL[i])); + TemplateArgManglingInfo Info(*this, TN); + for (unsigned i = 0, e = AL.size(); i != e; ++i) { + mangleTemplateArg(Info, i, AL[i]); + } + mangleRequiresClause(Info.getTrailingRequiresClauseToMangle()); Out << 'E'; } void CXXNameMangler::mangleTemplateArgs(TemplateName TN, ArrayRef<TemplateArgument> Args) { - // <template-args> ::= I <template-arg>+ E + // <template-args> ::= I <template-arg>+ [Q <requires-clause expr>] E Out << 'I'; - TemplateArgManglingInfo Info(TN); - for (unsigned i = 0; i != Args.size(); ++i) - mangleTemplateArg(Args[i], Info.needExactType(i, Args[i])); + TemplateArgManglingInfo Info(*this, TN); + for (unsigned i = 0; i != Args.size(); ++i) { + mangleTemplateArg(Info, i, Args[i]); + } + mangleRequiresClause(Info.getTrailingRequiresClauseToMangle()); Out << 'E'; } +void CXXNameMangler::mangleTemplateArg(TemplateArgManglingInfo &Info, + unsigned Index, TemplateArgument A) { + TemplateArgManglingInfo::Info ArgInfo = Info.getArgInfo(Index, A); + + // Proposed on https://github.com/itanium-cxx-abi/cxx-abi/issues/47. + if (ArgInfo.TemplateParameterToMangle && + !isCompatibleWith(LangOptions::ClangABI::Ver17)) { + // The template parameter is mangled if the mangling would otherwise be + // ambiguous. + // + // <template-arg> ::= <template-param-decl> <template-arg> + // + // Clang 17 and before did not do this. + mangleTemplateParamDecl(ArgInfo.TemplateParameterToMangle); + } + + mangleTemplateArg(A, ArgInfo.NeedExactType); +} + void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) { // <template-arg> ::= <type> # type or template // ::= X <expression> E # expression @@ -5604,8 +5925,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) { else if (D->getType()->isArrayType() && Ctx.hasSimilarType(Ctx.getDecayedType(D->getType()), A.getParamTypeForDecl()) && - Ctx.getLangOpts().getClangABICompat() > - LangOptions::ClangABI::Ver11) + !isCompatibleWith(LangOptions::ClangABI::Ver11)) // Build a value corresponding to this implicit array-to-pointer decay. Value = APValue(APValue::LValueBase(D), CharUnits::Zero(), {APValue::LValuePathEntry::ArrayIndex(0)}, @@ -5634,8 +5954,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) { } void CXXNameMangler::mangleTemplateArgExpr(const Expr *E) { - ASTContext &Ctx = Context.getASTContext(); - if (Ctx.getLangOpts().getClangABICompat() > LangOptions::ClangABI::Ver11) { + if (!isCompatibleWith(LangOptions::ClangABI::Ver11)) { mangleExpression(E, UnknownArity, /*AsTemplateArg=*/true); return; } @@ -6051,8 +6370,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, } else { if (NeedExactType && !Ctx.hasSameType(T->getPointeeType(), getLValueType(Ctx, V)) && - Ctx.getLangOpts().getClangABICompat() > - LangOptions::ClangABI::Ver11) { + !isCompatibleWith(LangOptions::ClangABI::Ver11)) { NotPrimaryExpr(); Out << "cv"; mangleType(T); @@ -6150,8 +6468,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, !Ctx.hasSameType( T->castAs<MemberPointerType>()->getPointeeType(), V.getMemberPointerDecl()->getType()) && - Ctx.getLangOpts().getClangABICompat() > - LangOptions::ClangABI::Ver11) { + !isCompatibleWith(LangOptions::ClangABI::Ver11)) { Out << "cv"; mangleType(T); } @@ -6182,6 +6499,7 @@ void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) { // The latter two manglings are from a proposal here: // https://github.com/itanium-cxx-abi/cxx-abi/issues/31#issuecomment-528122117 Out << 'T'; + Depth += TemplateDepthOffset; if (Depth != 0) Out << 'L' << (Depth - 1) << '_'; if (Index != 0) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index ffb4f30..9293b91 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 d2715db..99b4931 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3493,11 +3493,11 @@ ExprResult Parser::ParseRequiresExpression() { SourceLocation RequiresKWLoc = ConsumeToken(); // Consume 'requires' llvm::SmallVector<ParmVarDecl *, 2> LocalParameterDecls; + BalancedDelimiterTracker Parens(*this, tok::l_paren); if (Tok.is(tok::l_paren)) { // requirement parameter list is present. ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope | Scope::DeclScope); - BalancedDelimiterTracker Parens(*this, tok::l_paren); Parens.consumeOpen(); if (!Tok.is(tok::r_paren)) { ParsedAttributes FirstArgAttrs(getAttrFactory()); @@ -3769,8 +3769,9 @@ ExprResult Parser::ParseRequiresExpression() { Braces.consumeClose(); Actions.ActOnFinishRequiresExpr(); ParsingBodyDecl.complete(Body); - return Actions.ActOnRequiresExpr(RequiresKWLoc, Body, LocalParameterDecls, - Requirements, Braces.getCloseLocation()); + return Actions.ActOnRequiresExpr( + RequiresKWLoc, Body, Parens.getOpenLocation(), LocalParameterDecls, + Parens.getCloseLocation(), Requirements, Braces.getCloseLocation()); } static TypeTrait TypeTraitFromTokKind(tok::TokenKind kind) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 7728959..c147cc5 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -9191,14 +9191,14 @@ void Sema::ActOnFinishRequiresExpr() { assert(CurContext && "Popped translation unit!"); } -ExprResult -Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc, - RequiresExprBodyDecl *Body, - ArrayRef<ParmVarDecl *> LocalParameters, - ArrayRef<concepts::Requirement *> Requirements, - SourceLocation ClosingBraceLoc) { - auto *RE = RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, - Requirements, ClosingBraceLoc); +ExprResult Sema::ActOnRequiresExpr( + SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, + SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters, + SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements, + SourceLocation ClosingBraceLoc) { + auto *RE = RequiresExpr::Create(Context, RequiresKWLoc, Body, LParenLoc, + LocalParameters, RParenLoc, Requirements, + ClosingBraceLoc); if (DiagnoseUnexpandedParameterPackInRequiresExpr(RE)) return ExprError(); return RE; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index c723e47..00a3669 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 603a232..0fc5ad8 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -549,7 +549,8 @@ public: DeclarationNameInfo TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); - bool TransformRequiresExprRequirements(ArrayRef<concepts::Requirement *> Reqs, + bool TransformRequiresExprRequirements( + ArrayRef<concepts::Requirement *> Reqs, llvm::SmallVectorImpl<concepts::Requirement *> &Transformed); concepts::TypeRequirement * TransformTypeRequirement(concepts::TypeRequirement *Req); @@ -3616,11 +3617,14 @@ public: /// Subclasses may override this routine to provide different behavior. ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, + SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters, + SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements, SourceLocation ClosingBraceLoc) { - return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body, - LocalParameters, Requirements, ClosingBraceLoc); + return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body, LParenLoc, + LocalParameters, RParenLoc, Requirements, + ClosingBraceLoc); } concepts::TypeRequirement * @@ -12968,9 +12972,9 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) { } } - return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body, - TransParams, TransReqs, - E->getRBraceLoc()); + return getDerived().RebuildRequiresExpr( + E->getRequiresKWLoc(), Body, E->getLParenLoc(), TransParams, + E->getRParenLoc(), TransReqs, E->getRBraceLoc()); } template<typename Derived> diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index b9d9349..8edb04f 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -920,6 +920,8 @@ void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) { } std::copy(Requirements.begin(), Requirements.end(), E->getTrailingObjects<concepts::Requirement *>()); + E->LParenLoc = Record.readSourceLocation(); + E->RParenLoc = Record.readSourceLocation(); E->RBraceLoc = Record.readSourceLocation(); } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 94d3f94..125ca17 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; |