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