On Thu, 5 Sep 2019 at 17:39, Nico Weber via cfe-commits < cfe-commits@lists.llvm.org> wrote:
> 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? > Thanks, r371252. > 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 >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits