sepavloff added you to the CC list for the revision "PR12262 - assertion when
substituting explicit template arguments does not substitute a sizeof-pack
expression.".
Hi all,
This patch fixes PR12262 - assertion when substituting explicit template
arguments does not substitute a sizeof-pack expression. When sizeof...(pack) is
used in function declaration, it cannot be calculated until all parameters are
deduced from the function arguments. So during substitution of explicit
parameters, which takes place before parameter deduction, the pack is
represented by its name. However this name isn't present in current scope ,
this causes assertion failure. As a solution, introduce parameter pack into
the instantiation scope. Similar approach is used when instantiating template
methods.
Please review the fix.
Thank you.
http://llvm-reviews.chandlerc.com/D869
Files:
include/clang/AST/DeclTemplate.h
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -948,6 +948,15 @@
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
unsigned ID);
+ /// \brief Creates a copy of this template type parameter.
+ ///
+ /// \param C AST context in which the new parameter is created.
+ /// \param DC Declaration context of the new parameter.
+ /// \param RelDepth Relative depth of the new parameter.
+ /// \returns Pointer to the created copy.
+ TemplateTypeParmDecl *Clone(const ASTContext &C, DeclContext *DC,
+ unsigned RelDepth);
+
/// \brief Whether this template type parameter was declared with
/// the 'typename' keyword.
///
@@ -1068,7 +1077,6 @@
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned
NumExpandedTypes);
-
using TemplateParmPosition::getDepth;
using TemplateParmPosition::setDepth;
using TemplateParmPosition::getPosition;
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -468,6 +468,19 @@
0, false);
}
+TemplateTypeParmDecl *
+TemplateTypeParmDecl::Clone(const ASTContext &C, DeclContext *DC,
+ unsigned RelDepth) {
+ assert(RelDepth <= getDepth());
+ TemplateTypeParmDecl *Result;
+ Result = Create(C, DC, getLocStart(), getLocation(), getDepth() - RelDepth,
+ getIndex(), getIdentifier(), wasDeclaredWithTypename(),
+ isParameterPack());
+ if (hasDefaultArgument())
+ Result->setDefaultArgument(getDefaultArgumentInfo(), false);
+ return Result;
+}
+
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
return hasDefaultArgument()
? DefaultArgument->getTypeLoc().getBeginLoc()
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -3133,6 +3133,36 @@
LocalInstantiationScope InstScope(*this);
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
+
+ // If function template parameters contain a pack, the latter cannot be
+ // expanded until all parameters are deduced from the function arguments.
+ // If the pack is referenced in the declaration, will be represented by
+ // name. For instance (PR12262):
+ // \code
+ // template <unsigned N> class array {};
+ // template<typename T, typename... Types>
+ // array<sizeof...(Types)> make_array(Types&&... args);
+ // ...
+ // auto arr = make_array<int>(1,2,3);
+ // \endcode
+ // In this case when the explicit parameter is substituted, the pack remains
+ // unexpanded. It should be represented by a named declaration, use the
+ // parameter declaration for this purpose.
+ assert(TemplateParams);
+ for (TemplateParameterList::iterator Param = TemplateParams->begin(),
+ ParamEnd = TemplateParams->end();
+ Param != ParamEnd; ++Param) {
+ if (TemplateTypeParmDecl *D = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ if (D->isParameterPack()) {
+ TemplateTypeParmDecl *Inst = D->Clone(Context, 0, 0);
+ Inst->setAccess(AS_public);
+ // Introduce this template parameter's instantiation into the
+ // instantiation scope.
+ CurrentInstantiationScope->InstantiatedLocal(D, Inst);
+ }
+ }
+ }
+
SmallVector<DeducedTemplateArgument, 4> Deduced;
SmallVector<QualType, 4> ParamTypes;
unsigned NumExplicitlySpecified = 0;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1760,18 +1760,9 @@
// TODO: don't always clone when decls are refcounted.
assert(D->getTypeForDecl()->isTemplateTypeParmType());
- TemplateTypeParmDecl *Inst =
- TemplateTypeParmDecl::Create(SemaRef.Context, Owner,
- D->getLocStart(), D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getIndex(), D->getIdentifier(),
- D->wasDeclaredWithTypename(),
- D->isParameterPack());
+ TemplateTypeParmDecl *Inst = D->Clone(SemaRef.Context, Owner,
+ TemplateArgs.getNumLevels());
Inst->setAccess(AS_public);
-
- if (D->hasDefaultArgument())
- Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
-
// Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst);
Index: test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
===================================================================
--- /dev/null
+++ test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// PR12262
+
+template<typename T, typename... Ts>
+void abc1(int (*xxx)[sizeof ... (Ts) + 1]);
+
+void qq1 () {
+ abc1<int>(0);
+ abc1<int,double>(0);
+}
+
+
+template <unsigned N> class array {};
+
+
+template<typename T, typename... Types>
+array<sizeof...(Types)> make_array1(Types&&... args);
+
+void qq2 () {
+ array<1> arr = make_array1<int>(1);
+ array<3> arr2 = make_array1<int>(1,array<5>(),0.1);
+}
+
+
+template<typename T, typename... Types>
+int make_array(array<sizeof...(Types)>&, Types... args);
+
+void qq3 () {
+ array<1> a1;
+ int aa1 = make_array<int>(a1,1);
+ array<2> a2;
+ int aa2 = make_array<int>(a2, 0L, "abc");
+}
+
+
+template<typename ... Ts>
+struct AAA {
+ template<typename T, typename... Types>
+ static array<sizeof...(Types)> make_array(Types ... args);
+};
+
+void qq4 () {
+ array<2> arr2 = AAA<int, int>::make_array<int>(1,2);
+}
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -948,6 +948,15 @@
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
unsigned ID);
+ /// \brief Creates a copy of this template type parameter.
+ ///
+ /// \param C AST context in which the new parameter is created.
+ /// \param DC Declaration context of the new parameter.
+ /// \param RelDepth Relative depth of the new parameter.
+ /// \returns Pointer to the created copy.
+ TemplateTypeParmDecl *Clone(const ASTContext &C, DeclContext *DC,
+ unsigned RelDepth);
+
/// \brief Whether this template type parameter was declared with
/// the 'typename' keyword.
///
@@ -1068,7 +1077,6 @@
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned NumExpandedTypes);
-
using TemplateParmPosition::getDepth;
using TemplateParmPosition::setDepth;
using TemplateParmPosition::getPosition;
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -468,6 +468,19 @@
0, false);
}
+TemplateTypeParmDecl *
+TemplateTypeParmDecl::Clone(const ASTContext &C, DeclContext *DC,
+ unsigned RelDepth) {
+ assert(RelDepth <= getDepth());
+ TemplateTypeParmDecl *Result;
+ Result = Create(C, DC, getLocStart(), getLocation(), getDepth() - RelDepth,
+ getIndex(), getIdentifier(), wasDeclaredWithTypename(),
+ isParameterPack());
+ if (hasDefaultArgument())
+ Result->setDefaultArgument(getDefaultArgumentInfo(), false);
+ return Result;
+}
+
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
return hasDefaultArgument()
? DefaultArgument->getTypeLoc().getBeginLoc()
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -3133,6 +3133,36 @@
LocalInstantiationScope InstScope(*this);
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
+
+ // If function template parameters contain a pack, the latter cannot be
+ // expanded until all parameters are deduced from the function arguments.
+ // If the pack is referenced in the declaration, will be represented by
+ // name. For instance (PR12262):
+ // \code
+ // template <unsigned N> class array {};
+ // template<typename T, typename... Types>
+ // array<sizeof...(Types)> make_array(Types&&... args);
+ // ...
+ // auto arr = make_array<int>(1,2,3);
+ // \endcode
+ // In this case when the explicit parameter is substituted, the pack remains
+ // unexpanded. It should be represented by a named declaration, use the
+ // parameter declaration for this purpose.
+ assert(TemplateParams);
+ for (TemplateParameterList::iterator Param = TemplateParams->begin(),
+ ParamEnd = TemplateParams->end();
+ Param != ParamEnd; ++Param) {
+ if (TemplateTypeParmDecl *D = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ if (D->isParameterPack()) {
+ TemplateTypeParmDecl *Inst = D->Clone(Context, 0, 0);
+ Inst->setAccess(AS_public);
+ // Introduce this template parameter's instantiation into the
+ // instantiation scope.
+ CurrentInstantiationScope->InstantiatedLocal(D, Inst);
+ }
+ }
+ }
+
SmallVector<DeducedTemplateArgument, 4> Deduced;
SmallVector<QualType, 4> ParamTypes;
unsigned NumExplicitlySpecified = 0;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1760,18 +1760,9 @@
// TODO: don't always clone when decls are refcounted.
assert(D->getTypeForDecl()->isTemplateTypeParmType());
- TemplateTypeParmDecl *Inst =
- TemplateTypeParmDecl::Create(SemaRef.Context, Owner,
- D->getLocStart(), D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getIndex(), D->getIdentifier(),
- D->wasDeclaredWithTypename(),
- D->isParameterPack());
+ TemplateTypeParmDecl *Inst = D->Clone(SemaRef.Context, Owner,
+ TemplateArgs.getNumLevels());
Inst->setAccess(AS_public);
-
- if (D->hasDefaultArgument())
- Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false);
-
// Introduce this template parameter's instantiation into the instantiation
// scope.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Inst);
Index: test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
===================================================================
--- /dev/null
+++ test/CXX/temp/temp.decls/temp.variadic/sizeofpack.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// PR12262
+
+template<typename T, typename... Ts>
+void abc1(int (*xxx)[sizeof ... (Ts) + 1]);
+
+void qq1 () {
+ abc1<int>(0);
+ abc1<int,double>(0);
+}
+
+
+template <unsigned N> class array {};
+
+
+template<typename T, typename... Types>
+array<sizeof...(Types)> make_array1(Types&&... args);
+
+void qq2 () {
+ array<1> arr = make_array1<int>(1);
+ array<3> arr2 = make_array1<int>(1,array<5>(),0.1);
+}
+
+
+template<typename T, typename... Types>
+int make_array(array<sizeof...(Types)>&, Types... args);
+
+void qq3 () {
+ array<1> a1;
+ int aa1 = make_array<int>(a1,1);
+ array<2> a2;
+ int aa2 = make_array<int>(a2, 0L, "abc");
+}
+
+
+template<typename ... Ts>
+struct AAA {
+ template<typename T, typename... Types>
+ static array<sizeof...(Types)> make_array(Types ... args);
+};
+
+void qq4 () {
+ array<2> arr2 = AAA<int, int>::make_array<int>(1,2);
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits