aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ExprCXX.h67
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h1
-rw-r--r--include/clang/Basic/StmtNodes.td1
-rw-r--r--include/clang/Serialization/ASTBitCodes.h1
-rw-r--r--lib/AST/Expr.cpp1
-rw-r--r--lib/AST/ExprCXX.cpp28
-rw-r--r--lib/AST/ExprClassification.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp1
-rw-r--r--lib/AST/ItaniumMangle.cpp10
-rw-r--r--lib/AST/StmtPrinter.cpp4
-rw-r--r--lib/AST/StmtProfile.cpp8
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp93
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp3
-rw-r--r--lib/Sema/TreeTransform.h7
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp15
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp11
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp24
-rw-r--r--test/PCH/cxx-templates.cpp19
-rw-r--r--test/PCH/cxx-templates.h5
-rw-r--r--tools/libclang/CXCursor.cpp1
-rw-r--r--tools/libclang/RecursiveASTVisitor.h1
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<typename...Ts> struct S {
+/// template<typename...Us> auto f(Ts ...ts) -> decltype(g(Us(ts)...));
+/// };
+/// template struct S<int, int>;
+/// \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<Decl*> 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<iterator>(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<Expr>;
def SizeOfPackExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmExpr : DStmt<Expr>;
def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>;
+def FunctionParmPackExpr : DStmt<Expr>;
def MaterializeTemporaryExpr : DStmt<Expr>;
def LambdaExpr : DStmt<Expr>;
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<Decl**>(this+1));
+}
+
+FunctionParmPackExpr *
+FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
+ ParmVarDecl *ParamPack, SourceLocation NameLoc,
+ llvm::ArrayRef<Decl*> 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<TypeSourceInfo *> 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<FunctionParmPackExpr>(E);
+ Out << "v110_SUBSTPACK";
+ mangleFunctionParam(FPPE->getParameterPack());
+ break;
+ }
+
case Expr::DependentScopeDeclRefExprClass: {
const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(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,
@@ -1230,8 +1243,81 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
}
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<ValueDecl>(TransformDecl(E->getExprLoc(), D));
+ if (!VD)
+ return ExprError();
+ return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(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<Decl*, 8> Parms;
+ Parms.reserve(E->getNumExpansions());
+ for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
+ I != End; ++I) {
+ ParmVarDecl *D =
+ cast_or_null<ParmVarDecl>(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<Decl *, DeclArgumentPack *> *Found
+ = getSema().CurrentInstantiationScope->findInstantiationOf(PD);
+ assert(Found && "no instantiation for parameter pack");
+
+ Decl *TransformedDecl;
+ if (DeclArgumentPack *Pack = Found->dyn_cast<DeclArgumentPack *>()) {
+ // 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<Decl*>();
+ }
+
+ // We have either an unexpanded pack or a specific expansion.
+ return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(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<NonTypeTemplateParmDecl>(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<ParmVarDecl>(D))
+ if (PD->isParameterPack())
+ return TransformFunctionParmPackRefExpr(E, PD);
+
return TreeTransform<TemplateInstantiator>::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<Decl *>())
return cast<NamedDecl>(FD);
- unsigned PackIdx = ArgumentPackSubstitutionIndex;
+ int PackIdx = ArgumentPackSubstitutionIndex;
+ assert(PackIdx != -1 && "found declaration pack but not pack expanding");
return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[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
@@ -8321,6 +8321,13 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
+ // Default behavior is to do nothing with this transformation.
+ return SemaRef.Owned(E);
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformMaterializeTemporaryExpr(
MaterializeTemporaryExpr *E) {
return getDerived().TransformExpr(E->GetTemporaryExpr());
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<ParmVarDecl>(Record, Idx);
+ E->NameLoc = ReadSourceLocation(Record, Idx);
+ ParmVarDecl **Parms = reinterpret_cast<ParmVarDecl**>(E+1);
+ for (unsigned i = 0, n = E->NumParameters; i != n; ++i)
+ Parms[i] = ReadDeclAs<ParmVarDecl>(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<float>,
add_const<double>>>::value == 0? 1 : -1];
+ namespace PR13811 {
+ constexpr int g(int n, int m) { return n * 10 + m; }
+
+ template<typename...A>
+ struct X6 {
+ template<typename...B>
+ constexpr auto f1(A ...a) -> decltype(g(A(a + B())...)) { return g(A(a + B())...); }
+
+ template<typename...B>
+ constexpr auto f2(A ...a, B ...b) -> decltype(g((&a)[b] ...)) { return g((&a)[b] ...); } // expected-note {{past-the-end}}
+
+ template<typename...B> struct Inner {
+ template<typename...C>
+ 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<unsigned char, int>().f1<A, B>(255, 1) == 12, "");
+ static_assert(X6<int, int>().f2(3, 4, 0, 0) == 34, "");
+ static_assert(X6<int, int>().f2(3, 4, 0, 1) == 34, ""); // expected-error {{constant expression}} expected-note {{in call}}
+ static_assert(X6<int, int>::Inner<int, int>().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<char, char, char>().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<typename...A> struct NestedExpansion {
+ template<typename...B> auto f(A...a, B...b) -> decltype(g(a + b...));
+};
+template struct NestedExpansion<char, char, char>;
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, { })