On Wed, Sep 4, 2019 at 9:22 PM Richard Smith via cfe-commits < cfe-commits@lists.llvm.org> wrote:
> Author: rsmith > Date: Wed Sep 4 18:23:47 2019 > New Revision: 371004 > > URL: http://llvm.org/viewvc/llvm-project?rev=371004&view=rev > Log: > [c++20] Fix some ambiguities in our mangling of lambdas with explicit > template parameters. > > This finishes the implementation of the proposal described in > https://github.com/itanium-cxx-abi/cxx-abi/issues/31. (We already > implemented the <lambda-sig> extensions, but didn't take them into > account when computing mangling numbers, and didn't deal properly with > expanded parameter packs, and didn't disambiguate between different > levels of template parameters in manglings.) > > Modified: > cfe/trunk/include/clang/AST/Mangle.h > cfe/trunk/lib/AST/DeclBase.cpp > cfe/trunk/lib/AST/ItaniumCXXABI.cpp > cfe/trunk/lib/AST/ItaniumMangle.cpp > cfe/trunk/lib/Sema/SemaLambda.cpp > cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp > > Modified: cfe/trunk/include/clang/AST/Mangle.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=371004&r1=371003&r2=371004&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/AST/Mangle.h (original) > +++ cfe/trunk/include/clang/AST/Mangle.h Wed Sep 4 18:23:47 2019 > @@ -170,6 +170,8 @@ public: > virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D, > raw_ostream &) = 0; > > + virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream > &) = 0; > + > static bool classof(const MangleContext *C) { > return C->getKind() == MK_Itanium; > } > > Modified: cfe/trunk/lib/AST/DeclBase.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=371004&r1=371003&r2=371004&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/DeclBase.cpp (original) > +++ cfe/trunk/lib/AST/DeclBase.cpp Wed Sep 4 18:23:47 2019 > @@ -12,6 +12,7 @@ > > #include "clang/AST/DeclBase.h" > #include "clang/AST/ASTContext.h" > +#include "clang/AST/ASTLambda.h" > #include "clang/AST/ASTMutationListener.h" > #include "clang/AST/Attr.h" > #include "clang/AST/AttrIterator.h" > @@ -1043,6 +1044,12 @@ DeclContext *DeclContext::getLookupParen > getLexicalParent()->getRedeclContext()->isRecord()) > return getLexicalParent(); > > + // A lookup within the call operator of a lambda never looks in the > lambda > + // class; instead, skip to the context in which that closure type is > + // declared. > + if (isLambdaCallOperator(this)) > + return getParent()->getParent(); > + > return getParent(); > } > > > Modified: cfe/trunk/lib/AST/ItaniumCXXABI.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumCXXABI.cpp?rev=371004&r1=371003&r2=371004&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/ItaniumCXXABI.cpp (original) > +++ cfe/trunk/lib/AST/ItaniumCXXABI.cpp Wed Sep 4 18:23:47 2019 > @@ -19,10 +19,12 @@ > #include "CXXABI.h" > #include "clang/AST/ASTContext.h" > #include "clang/AST/DeclCXX.h" > +#include "clang/AST/Mangle.h" > #include "clang/AST/MangleNumberingContext.h" > #include "clang/AST/RecordLayout.h" > #include "clang/AST/Type.h" > #include "clang/Basic/TargetInfo.h" > +#include "llvm/ADT/FoldingSet.h" > #include "llvm/ADT/iterator.h" > > using namespace clang; > @@ -73,10 +75,33 @@ struct DecompositionDeclName { > } > > namespace llvm { > +template<typename T> bool isDenseMapKeyEmpty(T V) { > + return llvm::DenseMapInfo<T>::isEqual( > + V, llvm::DenseMapInfo<T>::getEmptyKey()); > +} > +template<typename T> bool isDenseMapKeyTombstone(T V) { > + return llvm::DenseMapInfo<T>::isEqual( > + V, llvm::DenseMapInfo<T>::getTombstoneKey()); > +} > + > +template<typename T> > +Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) { > + bool LHSEmpty = isDenseMapKeyEmpty(LHS); > + bool RHSEmpty = isDenseMapKeyEmpty(RHS); > + if (LHSEmpty || RHSEmpty) > + return LHSEmpty && RHSEmpty; > + > + bool LHSTombstone = isDenseMapKeyTombstone(LHS); > + bool RHSTombstone = isDenseMapKeyTombstone(RHS); > + if (LHSTombstone || RHSTombstone) > + return LHSTombstone && RHSTombstone; > + > + return None; > +} > + > template<> > struct DenseMapInfo<DecompositionDeclName> { > using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>; > - using IdentInfo = llvm::DenseMapInfo<const IdentifierInfo*>; > static DecompositionDeclName getEmptyKey() { > return {ArrayInfo::getEmptyKey()}; > } > @@ -88,10 +113,10 @@ struct DenseMapInfo<DecompositionDeclNam > return llvm::hash_combine_range(Key.begin(), Key.end()); > } > static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName > RHS) { > - if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getEmptyKey())) > - return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getEmptyKey()); > - if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getTombstoneKey())) > - return ArrayInfo::isEqual(RHS.Bindings, > ArrayInfo::getTombstoneKey()); > + if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues( > + LHS.Bindings, RHS.Bindings)) > + return *Result; > + > return LHS.Bindings.size() == RHS.Bindings.size() && > std::equal(LHS.begin(), LHS.end(), RHS.begin()); > } > @@ -103,29 +128,32 @@ namespace { > /// Keeps track of the mangled names of lambda expressions and block > /// literals within a particular context. > class ItaniumNumberingContext : public MangleNumberingContext { > - llvm::DenseMap<const Type *, unsigned> ManglingNumbers; > + ItaniumMangleContext *Mangler; > + llvm::StringMap<unsigned> LambdaManglingNumbers; > + unsigned BlockManglingNumber = 0; > llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers; > llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers; > llvm::DenseMap<DecompositionDeclName, unsigned> > DecompsitionDeclManglingNumbers; > > public: > + ItaniumNumberingContext(ItaniumMangleContext *Mangler) : > Mangler(Mangler) {} > + > unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { > - const FunctionProtoType *Proto = > - CallOperator->getType()->getAs<FunctionProtoType>(); > - ASTContext &Context = CallOperator->getASTContext(); > - > - FunctionProtoType::ExtProtoInfo EPI; > - EPI.Variadic = Proto->isVariadic(); > - QualType Key = > - Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), > EPI); > - Key = Context.getCanonicalType(Key); > - return ++ManglingNumbers[Key->castAs<FunctionProtoType>()]; > + const CXXRecordDecl *Lambda = CallOperator->getParent(); > + assert(Lambda->isLambda()); > + > + // Computation of the <lambda-sig> is non-trivial and subtle. Rather > than > + // duplicating it here, just mangle the <lambda-sig> directly. > + llvm::SmallString<128> LambdaSig; > + llvm::raw_svector_ostream Out(LambdaSig); > + Mangler->mangleLambdaSig(Lambda, Out); > + > + return ++LambdaManglingNumbers[LambdaSig]; > } > > unsigned getManglingNumber(const BlockDecl *BD) override { > - const Type *Ty = nullptr; > - return ++ManglingNumbers[Ty]; > + return ++BlockManglingNumber; > } > > unsigned getStaticLocalNumber(const VarDecl *VD) override { > @@ -154,10 +182,13 @@ public: > }; > > class ItaniumCXXABI : public CXXABI { > +private: > + std::unique_ptr<MangleContext> Mangler; > protected: > ASTContext &Context; > public: > - ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { } > + ItaniumCXXABI(ASTContext &Ctx) > + : Mangler(Ctx.createMangleContext()), Context(Ctx) {} > > MemberPointerInfo > getMemberPointerInfo(const MemberPointerType *MPT) const override { > @@ -218,7 +249,8 @@ public: > > std::unique_ptr<MangleNumberingContext> > createMangleNumberingContext() const override { > - return std::make_unique<ItaniumNumberingContext>(); > + return std::make_unique<ItaniumNumberingContext>( > + cast<ItaniumMangleContext>(Mangler.get())); > } > }; > } > > Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=371004&r1=371003&r2=371004&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) > +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Sep 4 18:23:47 2019 > @@ -170,6 +170,8 @@ public: > > void mangleStringLiteral(const StringLiteral *, raw_ostream &) override; > > + void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) > override; > + > bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { > // Lambda closure types are already numbered. > if (isLambda(ND)) > @@ -424,6 +426,7 @@ public: > void mangleName(const NamedDecl *ND); > void mangleType(QualType T); > void mangleNameOrStandardSubstitution(const NamedDecl *ND); > + void mangleLambdaSig(const CXXRecordDecl *Lambda); > > private: > > @@ -550,7 +553,7 @@ private: > void mangleTemplateArgs(const TemplateArgumentList &AL); > void mangleTemplateArg(TemplateArgument A); > > - void mangleTemplateParameter(unsigned Index); > + void mangleTemplateParameter(unsigned Depth, unsigned Index); > > void mangleFunctionParam(const ParmVarDecl *parm); > > @@ -965,7 +968,7 @@ void CXXNameMangler::mangleUnscopedTempl > if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) { > assert(!AdditionalAbiTags && > "template template param cannot have abi tags"); > - mangleTemplateParameter(TTP->getIndex()); > + mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); > } else if (isa<BuiltinTemplateDecl>(ND)) { > mangleUnscopedName(ND, AdditionalAbiTags); > } else { > @@ -1686,16 +1689,42 @@ void CXXNameMangler::mangleUnqualifiedBl > // ::= Tn <type> # template non-type parameter > // ::= Tt <template-param-decl>* E # template template parameter > ^ update comment? > void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) { > - if (isa<TemplateTypeParmDecl>(Decl)) { > + if (auto *Ty = dyn_cast<TemplateTypeParmDecl>(Decl)) { > + if (Ty->isParameterPack()) > + Out << "Tp"; > Out << "Ty"; > } else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) { > - Out << "Tn"; > - mangleType(Tn->getType()); > + if (Tn->isExpandedParameterPack()) { > + for (unsigned I = 0, N = Tn->getNumExpansionTypes(); I != N; ++I) { > + Out << "Tn"; > + mangleType(Tn->getExpansionType(I)); > + } > + } else { > + QualType T = Tn->getType(); > + if (Tn->isParameterPack()) { > + Out << "Tp"; > + T = T->castAs<PackExpansionType>()->getPattern(); > + } > + Out << "Tn"; > + mangleType(T); > + } > } else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) { > - Out << "Tt"; > - for (auto *Param : *Tt->getTemplateParameters()) > - mangleTemplateParamDecl(Param); > - Out << "E"; > + 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"; > + } > + } else { > + if (Tt->isParameterPack()) > + Out << "Tp"; > + Out << "Tt"; > + for (auto *Param : *Tt->getTemplateParameters()) > + mangleTemplateParamDecl(Param); > + Out << "E"; > + } > } > } > > @@ -1726,12 +1755,7 @@ void CXXNameMangler::mangleLambda(const > } > > Out << "Ul"; > - for (auto *D : Lambda->getLambdaExplicitTemplateParameters()) > - mangleTemplateParamDecl(D); > - const FunctionProtoType *Proto = > Lambda->getLambdaTypeInfo()->getType()-> > - getAs<FunctionProtoType>(); > - mangleBareFunctionType(Proto, /*MangleReturnType=*/false, > - Lambda->getLambdaStaticInvoker()); > + mangleLambdaSig(Lambda); > Out << "E"; > > // The number is omitted for the first closure type with a given > @@ -1746,6 +1770,15 @@ void CXXNameMangler::mangleLambda(const > Out << '_'; > } > > +void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) { > + for (auto *D : Lambda->getLambdaExplicitTemplateParameters()) > + mangleTemplateParamDecl(D); > + const FunctionProtoType *Proto = > Lambda->getLambdaTypeInfo()->getType()-> > + getAs<FunctionProtoType>(); > + mangleBareFunctionType(Proto, /*MangleReturnType=*/false, > + Lambda->getLambdaStaticInvoker()); > +} > + > void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { > switch (qualifier->getKind()) { > case NestedNameSpecifier::Global: > @@ -1852,7 +1885,7 @@ void CXXNameMangler::mangleTemplatePrefi > > // <template-template-param> ::= <template-param> > if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) { > - mangleTemplateParameter(TTP->getIndex()); > + mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); > } else { > manglePrefix(getEffectiveDeclContext(ND), NoFunction); > if (isa<BuiltinTemplateDecl>(ND)) > @@ -1885,8 +1918,8 @@ void CXXNameMangler::mangleType(Template > goto HaveDecl; > > HaveDecl: > - if (isa<TemplateTemplateParmDecl>(TD)) > - > mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex()); > + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD)) > + mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); > else > mangleName(TD); > break; > @@ -2964,7 +2997,7 @@ void CXXNameMangler::mangleType(const Me > > // <type> ::= <template-param> > void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { > - mangleTemplateParameter(T->getIndex()); > + mangleTemplateParameter(T->getDepth(), T->getIndex()); > } > > // <type> ::= <template-param> > @@ -3535,7 +3568,7 @@ void CXXNameMangler::mangleDeclRefExpr(c > > case Decl::NonTypeTemplateParm: > const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); > - mangleTemplateParameter(PD->getIndex()); > + mangleTemplateParameter(PD->getDepth(), PD->getIndex()); > break; > } > } > @@ -4264,13 +4297,13 @@ recurse: > Out << "sZ"; > const NamedDecl *Pack = SPE->getPack(); > if (const TemplateTypeParmDecl *TTP = > dyn_cast<TemplateTypeParmDecl>(Pack)) > - mangleTemplateParameter(TTP->getIndex()); > + mangleTemplateParameter(TTP->getDepth(), TTP->getIndex()); > else if (const NonTypeTemplateParmDecl *NTTP > = dyn_cast<NonTypeTemplateParmDecl>(Pack)) > - mangleTemplateParameter(NTTP->getIndex()); > + mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex()); > else if (const TemplateTemplateParmDecl *TempTP > = > dyn_cast<TemplateTemplateParmDecl>(Pack)) > - mangleTemplateParameter(TempTP->getIndex()); > + mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex()); > else > mangleFunctionParam(cast<ParmVarDecl>(Pack)); > break; > @@ -4557,13 +4590,21 @@ void CXXNameMangler::mangleTemplateArg(T > } > } > > -void CXXNameMangler::mangleTemplateParameter(unsigned Index) { > +void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned > Index) { > // <template-param> ::= T_ # first template parameter > // ::= T <parameter-2 non-negative number> _ > - if (Index == 0) > - Out << "T_"; > - else > - Out << 'T' << (Index - 1) << '_'; > + // ::= TL <L-1 non-negative number> __ > + // ::= TL <L-1 non-negative number> _ > + // <parameter-2 non-negative number> _ > + // > + // The latter two manglings are from a proposal here: > + // > https://github.com/itanium-cxx-abi/cxx-abi/issues/31#issuecomment-528122117 > + Out << 'T'; > + if (Depth != 0) > + Out << 'L' << (Depth - 1) << '_'; > + if (Index != 0) > + Out << (Index - 1); > + Out << '_'; > } > > void CXXNameMangler::mangleSeqID(unsigned SeqID) { > @@ -5080,6 +5121,12 @@ void ItaniumMangleContextImpl::mangleStr > llvm_unreachable("Can't mangle string literals"); > } > > +void ItaniumMangleContextImpl::mangleLambdaSig(const CXXRecordDecl > *Lambda, > + raw_ostream &Out) { > + CXXNameMangler Mangler(*this, Out); > + Mangler.mangleLambdaSig(Lambda); > +} > + > ItaniumMangleContext * > ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine > &Diags) { > return new ItaniumMangleContextImpl(Context, Diags); > > Modified: cfe/trunk/lib/Sema/SemaLambda.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=371004&r1=371003&r2=371004&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaLambda.cpp (original) > +++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Sep 4 18:23:47 2019 > @@ -407,6 +407,8 @@ CXXMethodDecl *Sema::startLambdaDefiniti > MethodType, MethodTypeInfo, SC_None, > /*isInline=*/true, ConstexprKind, EndLoc); > Method->setAccess(AS_public); > + if (!TemplateParams) > + Class->addDecl(Method); > > // Temporarily set the lexical declaration context to the current > // context, so that the Scope stack matches the lexical nesting. > @@ -418,9 +420,10 @@ CXXMethodDecl *Sema::startLambdaDefiniti > TemplateParams, > Method) : nullptr; > if (TemplateMethod) { > - TemplateMethod->setLexicalDeclContext(CurContext); > TemplateMethod->setAccess(AS_public); > Method->setDescribedFunctionTemplate(TemplateMethod); > + Class->addDecl(TemplateMethod); > + TemplateMethod->setLexicalDeclContext(CurContext); > } > > // Add parameters. > @@ -1641,8 +1644,9 @@ ExprResult Sema::BuildLambdaExpr(SourceL > ? CallOperator->getDescribedFunctionTemplate() > : cast<Decl>(CallOperator); > > + // FIXME: Is this really the best choice? Keeping the lexical decl > context > + // set as CurContext seems more faithful to the source. > TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class); > - Class->addDecl(TemplateOrNonTemplateCallOperatorDecl); > > PopExpressionEvaluationContext(); > > > Modified: > cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp?rev=371004&r1=371003&r2=371004&view=diff > > ============================================================================== > --- cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp > (original) > +++ cfe/trunk/test/CodeGenCXX/mangle-lambda-explicit-template-params.cpp > Wed Sep 4 18:23:47 2019 > @@ -33,9 +33,68 @@ void call_inline_func() { > inline_func(); > } > > +template<typename T, int> struct X {}; > + > +inline auto pack = []<typename ...T, T ...N>(T (&...)[N]) {}; > +int arr1[] = {1}; > +int arr2[] = {1, 2}; > +// CHECK: @_ZNK4packMUlTpTyTpTnT_DpRAT0__S_E_clIJiiEJLi1ELi2EEEEDaS2_( > +void use_pack() { pack(arr1, arr2); } > + > +inline void collision() { > + auto a = []<typename T, template<typename U, T> typename>{}; > + auto b = []<typename T, template<typename U, U> typename>{}; > + auto c = []<typename T, template<typename U, T> typename>{}; > + a.operator()<int, X>(); > + // CHECK: @_ZZ9collisionvENKUlTyTtTyTnT_EvE_clIi1XEEDav > + b.operator()<int, X>(); > + // CHECK: @_ZZ9collisionvENKUlTyTtTyTnTL0__EvE_clIi1XEEDav > + c.operator()<int, X>(); > + // CHECK: @_ZZ9collisionvENKUlTyTtTyTnT_EvE0_clIi1XEEDav > +} > +void use_collision() { collision(); } > + > template<typename> void f() { > // CHECK: define linkonce_odr {{.*}} @_ZZ1fIiEvvENKUlT_E_clIiEEDaS0_( > auto x = [](auto){}; > x(0); > } > void use_f() { f<int>(); } > + > +template<typename> struct Y { > + template<int> struct Z {}; > +}; > + > +template<typename ...T> void expanded() { > + auto x = []<T..., template<T> typename...>{}; > + auto y = []<int, template<int> typename>{}; > + auto z = []<int, int, template<int> typename, template<int> typename>{}; > + // FIXME: Should we really require 'template' for y and z? > + x.template operator()<(T())..., Y<T>::template Z...>(); > + y.template operator()<0, Y<int>::Z>(); > + y.template operator()<1, Y<int>::Z>(); > + z.template operator()<1, 2, Y<int>::Z, Y<float>::Z>(); > +} > +void use_expanded() { > + // CHECK: @_ZZ8expandedIJEEvvENKUlvE_clIJEJEEEDav( > + // CHECK: @_ZZ8expandedIJEEvvENKUlTniTtTniEvE_clILi0EN1YIiE1ZEEEDav( > + // CHECK: @_ZZ8expandedIJEEvvENKUlTniTtTniEvE_clILi1EN1YIiE1ZEEEDav( > + // CHECK: > @_ZZ8expandedIJEEvvENKUlTniTniTtTniETtTniEvE_clILi1ELi2EN1YIiE1ZENS2_IfE1ZEEEDav( > + expanded<>(); > + > + // FIXME: Should we really be using J...E for arguments corresponding > to an > + // expanded parameter pack? > + // Note that the <lambda-sig>s of 'x' and 'y' collide here, after pack > expansion. > + // CHECK: > @_ZZ8expandedIJiEEvvENKUlTniTtTniEvE_clIJLi0EEJN1YIiE1ZEEEEDav( > + // CHECK: @_ZZ8expandedIJiEEvvENKUlTniTtTniEvE0_clILi0EN1YIiE1ZEEEDav( > + // CHECK: @_ZZ8expandedIJiEEvvENKUlTniTtTniEvE0_clILi1EN1YIiE1ZEEEDav( > + // CHECK: > @_ZZ8expandedIJiEEvvENKUlTniTniTtTniETtTniEvE_clILi1ELi2EN1YIiE1ZENS2_IfE1ZEEEDav( > + expanded<int>(); > + > + // Note that the <lambda-sig>s of 'x' and 'z' collide here, after pack > expansion. > + // CHECK: > @_ZZ8expandedIJiiEEvvENKUlTniTniTtTniETtTniEvE_clIJLi0ELi0EEJN1YIiE1ZES4_EEEDav( > + // CHECK: @_ZZ8expandedIJiiEEvvENKUlTniTtTniEvE_clILi0EN1YIiE1ZEEEDav( > + // CHECK: @_ZZ8expandedIJiiEEvvENKUlTniTtTniEvE_clILi1EN1YIiE1ZEEEDav( > + // CHECK: > @_ZZ8expandedIJiiEEvvENKUlTniTniTtTniETtTniEvE0_clILi1ELi2EN1YIiE1ZENS2_IfE1ZEEEDav( > + expanded<int, int>(); > +} > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits