From 9a4db032ecd991626d236a502e770126db32bd31 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 12 Sep 2012 00:56:43 +0000 Subject: [PATCH] PR13811: Add a FunctionParmPackExpr node to handle references to function parameter packs where the reference is not being expanded but the pack has been. Previously, Clang would segfault in such cases. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163672 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprCXX.h | 67 +++++++++++++ include/clang/AST/RecursiveASTVisitor.h | 1 + include/clang/Basic/StmtNodes.td | 1 + include/clang/Serialization/ASTBitCodes.h | 1 + lib/AST/Expr.cpp | 1 + lib/AST/ExprCXX.cpp | 28 ++++++ lib/AST/ExprClassification.cpp | 1 + lib/AST/ExprConstant.cpp | 1 + lib/AST/ItaniumMangle.cpp | 10 +- lib/AST/StmtPrinter.cpp | 4 + lib/AST/StmtProfile.cpp | 8 ++ lib/Sema/SemaExceptionSpec.cpp | 1 + lib/Sema/SemaTemplateInstantiate.cpp | 93 ++++++++++++++++++- lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 +- lib/Sema/TreeTransform.h | 7 ++ lib/Serialization/ASTReaderStmt.cpp | 15 +++ lib/Serialization/ASTWriterStmt.cpp | 11 +++ lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + .../multi-level-substitution.cpp | 24 +++++ test/PCH/cxx-templates.cpp | 19 +++- test/PCH/cxx-templates.h | 5 + tools/libclang/CXCursor.cpp | 1 + tools/libclang/RecursiveASTVisitor.h | 1 + 23 files changed, 296 insertions(+), 8 deletions(-) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index eca0ff9379..0c4ca8e979 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -3616,6 +3616,73 @@ public: child_range children() { return child_range(); } }; +/// \brief Represents a reference to a function parameter pack that has been +/// substituted but not yet expanded. +/// +/// When a pack expansion contains multiple parameter packs at different levels, +/// this node is used to represent a function parameter pack at an outer level +/// which we have already substituted to refer to expanded parameters, but where +/// the containing pack expansion cannot yet be expanded. +/// +/// \code +/// template struct S { +/// template auto f(Ts ...ts) -> decltype(g(Us(ts)...)); +/// }; +/// template struct S; +/// \endcode +class FunctionParmPackExpr : public Expr { + /// \brief The function parameter pack which was referenced. + ParmVarDecl *ParamPack; + + /// \brief The location of the function parameter pack reference. + SourceLocation NameLoc; + + /// \brief The number of expansions of this pack. + unsigned NumParameters; + + FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, + SourceLocation NameLoc, unsigned NumParams, + Decl * const *Params); + + friend class ASTReader; + friend class ASTStmtReader; + +public: + static FunctionParmPackExpr *Create(ASTContext &Context, QualType T, + ParmVarDecl *ParamPack, + SourceLocation NameLoc, + llvm::ArrayRef Params); + static FunctionParmPackExpr *CreateEmpty(ASTContext &Context, + unsigned NumParams); + + /// \brief Get the parameter pack which this expression refers to. + ParmVarDecl *getParameterPack() const { return ParamPack; } + + /// \brief Get the location of the parameter pack. + SourceLocation getParameterPackLocation() const { return NameLoc; } + + /// \brief Iterators over the parameters which the parameter pack expanded + /// into. + typedef ParmVarDecl * const *iterator; + iterator begin() const { return reinterpret_cast(this+1); } + iterator end() const { return begin() + NumParameters; } + + /// \brief Get the number of parameters in this parameter pack. + unsigned getNumExpansions() const { return NumParameters; } + + /// \brief Get an expansion of the parameter pack by index. + ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; } + + SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FunctionParmPackExprClass; + } + static bool classof(const FunctionParmPackExpr *) { return true; } + + child_range children() { return child_range(); } +}; + /// \brief Represents a prvalue temporary that written into memory so that /// a reference can bind to it. /// diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index ae4ff4b1f8..22cd290858 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2221,6 +2221,7 @@ DEF_TRAVERSE_STMT(PackExpansionExpr, { }) DEF_TRAVERSE_STMT(SizeOfPackExpr, { }) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { }) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { }) +DEF_TRAVERSE_STMT(FunctionParmPackExpr, { }) DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { }) DEF_TRAVERSE_STMT(AtomicExpr, { }) diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 06da94708f..8f6a1c9f98 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -131,6 +131,7 @@ def PackExpansionExpr : DStmt; def SizeOfPackExpr : DStmt; def SubstNonTypeTemplateParmExpr : DStmt; def SubstNonTypeTemplateParmPackExpr : DStmt; +def FunctionParmPackExpr : DStmt; def MaterializeTemporaryExpr : DStmt; def LambdaExpr : DStmt; diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index e714da771b..5f127d252f 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1193,6 +1193,7 @@ namespace clang { EXPR_SIZEOF_PACK, // SizeOfPackExpr EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr + EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr // CUDA diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 2ede77ec03..ea82cf7531 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2646,6 +2646,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case UnresolvedMemberExprClass: case PackExpansionExprClass: case SubstNonTypeTemplateParmPackExprClass: + case FunctionParmPackExprClass: llvm_unreachable("shouldn't see dependent / unresolved nodes here"); case DeclRefExprClass: diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 72e17b7417..e6076f007f 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -1299,6 +1299,34 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { return TemplateArgument(Arguments, NumArguments); } +FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, + SourceLocation NameLoc, + unsigned NumParams, + Decl * const *Params) + : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, + true, true, true, true), + ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) { + if (Params) + std::uninitialized_copy(Params, Params + NumParams, + reinterpret_cast(this+1)); +} + +FunctionParmPackExpr * +FunctionParmPackExpr::Create(ASTContext &Context, QualType T, + ParmVarDecl *ParamPack, SourceLocation NameLoc, + llvm::ArrayRef Params) { + return new (Context.Allocate(sizeof(FunctionParmPackExpr) + + sizeof(ParmVarDecl*) * Params.size())) + FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data()); +} + +FunctionParmPackExpr * +FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) { + return new (Context.Allocate(sizeof(FunctionParmPackExpr) + + sizeof(ParmVarDecl*) * NumParams)) + FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0); +} + TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef Args, SourceLocation RParenLoc, diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index f16d70b5da..24ec6bb020 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // ObjC instance variables are lvalues // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: + case Expr::FunctionParmPackExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 2cd7f04e92..8f3f84d07d 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -6480,6 +6480,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::OpaqueValueExprClass: case Expr::PackExpansionExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::FunctionParmPackExprClass: case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::MaterializeTemporaryExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 0b8a4c89f8..1a663a055d 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2809,7 +2809,15 @@ recurse: // }; Out << "_SUBSTPACK_"; break; - + + case Expr::FunctionParmPackExprClass: { + // FIXME: not clear how to mangle this! + const FunctionParmPackExpr *FPPE = cast(E); + Out << "v110_SUBSTPACK"; + mangleFunctionParam(FPPE->getParameterPack()); + break; + } + case Expr::DependentScopeDeclRefExprClass: { const DependentScopeDeclRefExpr *DRE = cast(E); mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 0cf3aaf558..a64049b8d2 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1647,6 +1647,10 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmExpr( Visit(Node->getReplacement()); } +void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + OS << *E->getParameterPack(); +} + void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){ PrintExpr(Node->GetTemporaryExpr()); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 5d7f9f8ede..0c3186fec2 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -973,6 +973,14 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmExpr( Visit(E->getReplacement()); } +void StmtProfiler::VisitFunctionParmPackExpr(const FunctionParmPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getParameterPack()); + ID.AddInteger(S->getNumExpansions()); + for (FunctionParmPackExpr::iterator I = S->begin(), E = S->end(); I != E; ++I) + VisitDecl(*I); +} + void StmtProfiler::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *S) { VisitExpr(S); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index e6266fb086..e0e0d20310 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -1029,6 +1029,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::PseudoObjectExprClass: case Expr::SubstNonTypeTemplateParmExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::FunctionParmPackExprClass: case Expr::UnaryExprOrTypeTraitExprClass: case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index d3367c4ee9..fc8371bf21 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -802,11 +802,24 @@ namespace { ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); + ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); ExprResult TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); - + + /// \brief Rebuild a DeclRefExpr for a ParmVarDecl reference. + ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc); + + /// \brief Transform a reference to a function parameter pack. + ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, + ParmVarDecl *PD); + + /// \brief Transform a FunctionParmPackExpr which was built when we couldn't + /// expand a function parameter pack reference which refers to an expanded + /// pack. + ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL); QualType TransformFunctionProtoType(TypeLocBuilder &TLB, @@ -1229,9 +1242,82 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( Arg); } +ExprResult +TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD, + SourceLocation Loc) { + DeclarationNameInfo NameInfo(PD->getDeclName(), Loc); + return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD); +} + +ExprResult +TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { + if (getSema().ArgumentPackSubstitutionIndex != -1) { + // We can expand this parameter pack now. + ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex); + ValueDecl *VD = cast_or_null(TransformDecl(E->getExprLoc(), D)); + if (!VD) + return ExprError(); + return RebuildParmVarDeclRefExpr(cast(VD), E->getExprLoc()); + } + + QualType T = TransformType(E->getType()); + if (T.isNull()) + return ExprError(); + + // Transform each of the parameter expansions into the corresponding + // parameters in the instantiation of the function decl. + llvm::SmallVector Parms; + Parms.reserve(E->getNumExpansions()); + for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); + I != End; ++I) { + ParmVarDecl *D = + cast_or_null(TransformDecl(E->getExprLoc(), *I)); + if (!D) + return ExprError(); + Parms.push_back(D); + } + + return FunctionParmPackExpr::Create(getSema().Context, T, + E->getParameterPack(), + E->getParameterPackLocation(), Parms); +} + +ExprResult +TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E, + ParmVarDecl *PD) { + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + llvm::PointerUnion *Found + = getSema().CurrentInstantiationScope->findInstantiationOf(PD); + assert(Found && "no instantiation for parameter pack"); + + Decl *TransformedDecl; + if (DeclArgumentPack *Pack = Found->dyn_cast()) { + // If this is a reference to a function parameter pack which we can substitute + // but can't yet expand, build a FunctionParmPackExpr for it. + if (getSema().ArgumentPackSubstitutionIndex == -1) { + QualType T = TransformType(E->getType()); + if (T.isNull()) + return ExprError(); + return FunctionParmPackExpr::Create(getSema().Context, T, PD, + E->getExprLoc(), *Pack); + } + + TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex]; + } else { + TransformedDecl = Found->get(); + } + + // We have either an unexpanded pack or a specific expansion. + return RebuildParmVarDeclRefExpr(cast(TransformedDecl), + E->getExprLoc()); +} + ExprResult TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { NamedDecl *D = E->getDecl(); + + // Handle references to non-type template parameters and non-type template + // parameter packs. if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) { if (NTTP->getDepth() < TemplateArgs.getNumLevels()) return TransformTemplateParmRefExpr(E, NTTP); @@ -1240,6 +1326,11 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { // FindInstantiatedDecl will find it in the local instantiation scope. } + // Handle references to function parameter packs. + if (ParmVarDecl *PD = dyn_cast(D)) + if (PD->isParameterPack()) + return TransformFunctionParmPackRefExpr(E, PD); + return TreeTransform::TransformDeclRefExpr(E); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 55462ff09b..15afd1f6c9 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3397,7 +3397,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (Decl *FD = Found->dyn_cast()) return cast(FD); - unsigned PackIdx = ArgumentPackSubstitutionIndex; + int PackIdx = ArgumentPackSubstitutionIndex; + assert(PackIdx != -1 && "found declaration pack but not pack expanding"); return cast((*Found->get())[PackIdx]); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 0c1f1a42a0..3d9a6ca11b 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -8319,6 +8319,13 @@ TreeTransform::TransformSubstNonTypeTemplateParmExpr( return SemaRef.Owned(E); } +template +ExprResult +TreeTransform::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { + // Default behavior is to do nothing with this transformation. + return SemaRef.Owned(E); +} + template ExprResult TreeTransform::TransformMaterializeTemporaryExpr( diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 6ca450b9fb..cfe22b5208 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1468,6 +1468,16 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( E->NameLoc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + VisitExpr(E); + E->NumParameters = Record[Idx++]; + E->ParamPack = ReadDeclAs(Record, Idx); + E->NameLoc = ReadSourceLocation(Record, Idx); + ParmVarDecl **Parms = reinterpret_cast(E+1); + for (unsigned i = 0, n = E->NumParameters; i != n; ++i) + Parms[i] = ReadDeclAs(Record, Idx); +} + void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); E->Temporary = Reader.ReadSubExpr(); @@ -2183,6 +2193,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK: S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty); break; + + case EXPR_FUNCTION_PARM_PACK: + S = FunctionParmPackExpr::CreateEmpty(Context, + Record[ASTStmtReader::NumExprFields]); + break; case EXPR_MATERIALIZE_TEMPORARY: S = new (Context) MaterializeTemporaryExpr(Empty); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 5fa08d256c..9ca8130586 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1481,6 +1481,17 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr( Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK; } +void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumExpansions()); + Writer.AddDeclRef(E->getParameterPack(), Record); + Writer.AddSourceLocation(E->getParameterPackLocation(), Record); + for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); + I != End; ++I) + Writer.AddDeclRef(*I, Record); + Code = serialization::EXPR_FUNCTION_PARM_PACK; +} + void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); Writer.AddStmt(E->Temporary); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index d177b60a50..4d4faf6d0b 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -526,6 +526,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXNoexceptExprClass: case Stmt::PackExpansionExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: + case Stmt::FunctionParmPackExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::LambdaExprClass: diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp index 485068e648..e0ffef5007 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp @@ -187,6 +187,30 @@ namespace PacksAtDifferentLevels { add_pointer, add_const>>::value == 0? 1 : -1]; + namespace PR13811 { + constexpr int g(int n, int m) { return n * 10 + m; } + + template + struct X6 { + template + constexpr auto f1(A ...a) -> decltype(g(A(a + B())...)) { return g(A(a + B())...); } + + template + constexpr auto f2(A ...a, B ...b) -> decltype(g((&a)[b] ...)) { return g((&a)[b] ...); } // expected-note {{past-the-end}} + + template struct Inner { + template + constexpr auto f(A ...a, B ...b, C ...c) -> decltype(g(a+b+c...)) { return g(a+b+c...); } + }; + }; + struct A { constexpr operator int() { return 2; } }; + struct B { constexpr operator int() { return 1; } }; + + static_assert(X6().f1(255, 1) == 12, ""); + static_assert(X6().f2(3, 4, 0, 0) == 34, ""); + static_assert(X6().f2(3, 4, 0, 1) == 34, ""); // expected-error {{constant expression}} expected-note {{in call}} + static_assert(X6::Inner().f(1, 2, 3, 4, 5, 6) == 102, ""); + } } namespace ExpandingNonTypeTemplateParameters { diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp index 7ce247721f..6312ca9788 100644 --- a/test/PCH/cxx-templates.cpp +++ b/test/PCH/cxx-templates.cpp @@ -1,11 +1,11 @@ // Test this without pch. -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o - -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o - +// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s // Test with pch. -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o - -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h +// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o - +// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - | FileCheck %s // CHECK: define weak_odr void @_ZN2S4IiE1mEv // CHECK: define linkonce_odr void @_ZN2S3IiE1mEv @@ -68,3 +68,12 @@ Foo< D >& Foo< D >::operator=( const Foo& other ) { return *this; } + +namespace TestNestedExpansion { + struct Int { + Int(int); + friend Int operator+(Int, Int); + }; + Int &g(Int, int, double); + Int &test = NestedExpansion().f(0, 1, 2, Int(3), 4, 5.0); +} diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h index 152e8cef54..756f208b76 100644 --- a/test/PCH/cxx-templates.h +++ b/test/PCH/cxx-templates.h @@ -215,3 +215,8 @@ class Foo : protected T public: Foo& operator=( const Foo& other ); }; + +template struct NestedExpansion { + template auto f(A...a, B...b) -> decltype(g(a + b...)); +}; +template struct NestedExpansion; diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index e219f948ea..a8cb1f96d4 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -432,6 +432,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU, case Stmt::DependentScopeDeclRefExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: + case Stmt::FunctionParmPackExprClass: case Stmt::UnresolvedLookupExprClass: K = CXCursor_DeclRefExpr; break; diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h index ab96f36205..571bb82082 100644 --- a/tools/libclang/RecursiveASTVisitor.h +++ b/tools/libclang/RecursiveASTVisitor.h @@ -2141,6 +2141,7 @@ DEF_TRAVERSE_STMT(PackExpansionExpr, { }) DEF_TRAVERSE_STMT(SizeOfPackExpr, { }) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { }) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { }) +DEF_TRAVERSE_STMT(FunctionParmPackExpr, { }) DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { }) DEF_TRAVERSE_STMT(AtomicExpr, { }) -- 2.40.0