r371004 - [c++20] Fix some ambiguities in our mangling of lambdas with explicit
Nico Weber via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 5 17:39:33 PDT 2019
On Wed, Sep 4, 2019 at 9:22 PM Richard Smith via cfe-commits <
cfe-commits at 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 at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20190905/082e1017/attachment-0001.html>
More information about the cfe-commits
mailing list