r295696 - PR32010: Fix template argument depth mixup when forming implicit constructor
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 20 22:30:39 PST 2017
Author: rsmith
Date: Tue Feb 21 00:30:38 2017
New Revision: 295696
URL: http://llvm.org/viewvc/llvm-project?rev=295696&view=rev
Log:
PR32010: Fix template argument depth mixup when forming implicit constructor
template deduction guides for class template argument deduction.
Ensure that we have a local instantiation scope for tracking the instantiated
parameters. Additionally, unusually, we're substituting at depth 1 and leaving
depth 0 alone; make sure that we don't reduce template parameter depth by 2 for
inner parameters in the process. (This is probably also broken for alias
templates in the case where they're expanded within a dependent context, but
this patch doesn't fix that.)
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/Sema/Template.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
cfe/trunk/test/SemaTemplate/deduction.cpp
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=295696&r1=295695&r2=295696&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Tue Feb 21 00:30:38 2017
@@ -1479,6 +1479,7 @@ public:
unsigned NumExpansions);
using TemplateParmPosition::getDepth;
+ using TemplateParmPosition::setDepth;
using TemplateParmPosition::getPosition;
using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
Modified: cfe/trunk/include/clang/Sema/Template.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=295696&r1=295695&r2=295696&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Template.h (original)
+++ cfe/trunk/include/clang/Sema/Template.h Tue Feb 21 00:30:38 2017
@@ -46,6 +46,10 @@ namespace clang {
/// \brief The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
SmallVector<ArgList, 4> TemplateArgumentLists;
+
+ /// \brief The number of outer levels of template arguments that are not
+ /// being substituted.
+ unsigned NumRetainedOuterLevels = 0;
public:
/// \brief Construct an empty set of template argument lists.
@@ -59,11 +63,19 @@ namespace clang {
/// \brief Determine the number of levels in this template argument
/// list.
- unsigned getNumLevels() const { return TemplateArgumentLists.size(); }
-
+ unsigned getNumLevels() const {
+ return TemplateArgumentLists.size() + NumRetainedOuterLevels;
+ }
+
+ /// \brief Determine the number of substituted levels in this template
+ /// argument list.
+ unsigned getNumSubstitutedLevels() const {
+ return TemplateArgumentLists.size();
+ }
+
/// \brief Retrieve the template argument at a given depth and index.
const TemplateArgument &operator()(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
return TemplateArgumentLists[getNumLevels() - Depth - 1][Index];
}
@@ -73,7 +85,10 @@ namespace clang {
///
/// There must exist a template argument list at the given depth.
bool hasTemplateArgument(unsigned Depth, unsigned Index) const {
- assert(Depth < TemplateArgumentLists.size());
+ assert(Depth < getNumLevels());
+
+ if (Depth < NumRetainedOuterLevels)
+ return false;
if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].size())
return false;
@@ -84,7 +99,7 @@ namespace clang {
/// \brief Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
- assert(Depth < TemplateArgumentLists.size());
+ assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].size());
const_cast<TemplateArgument&>(
TemplateArgumentLists[getNumLevels() - Depth - 1][Index])
@@ -101,9 +116,18 @@ namespace clang {
/// \brief Add a new outmost level to the multi-level template argument
/// list.
void addOuterTemplateArguments(ArgList Args) {
+ assert(!NumRetainedOuterLevels &&
+ "substituted args outside retained args?");
TemplateArgumentLists.push_back(Args);
}
+ /// \brief Add an outermost level that we are not substituting. We have no
+ /// arguments at this level, and do not remove it from the depth of inner
+ /// template parameters that we instantiate.
+ void addOuterRetainedLevel() {
+ ++NumRetainedOuterLevels;
+ }
+
/// \brief Retrieve the innermost template argument list.
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=295696&r1=295695&r2=295696&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Feb 21 00:30:38 2017
@@ -1442,6 +1442,8 @@ struct ConvertConstructorToDeductionGuid
CXXConstructorDecl *CD) {
SmallVector<TemplateArgument, 16> SubstArgs;
+ LocalInstantiationScope Scope(SemaRef);
+
// C++ [over.match.class.deduct]p1:
// -- For each constructor of the class template designated by the
// template-name, a function template with the following properties:
@@ -1463,7 +1465,7 @@ struct ConvertConstructorToDeductionGuid
for (NamedDecl *Param : *InnerParams) {
MultiLevelTemplateArgumentList Args;
Args.addOuterTemplateArguments(SubstArgs);
- Args.addOuterTemplateArguments(None);
+ Args.addOuterRetainedLevel();
NamedDecl *NewParam = transformTemplateParameter(Param, Args);
if (!NewParam)
return nullptr;
@@ -1483,7 +1485,7 @@ struct ConvertConstructorToDeductionGuid
MultiLevelTemplateArgumentList Args;
if (FTD) {
Args.addOuterTemplateArguments(SubstArgs);
- Args.addOuterTemplateArguments(None);
+ Args.addOuterRetainedLevel();
}
FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
@@ -1555,6 +1557,8 @@ private:
if (InstantiatedDefaultArg)
NewTTP->setDefaultArgument(InstantiatedDefaultArg);
}
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(TemplateParam,
+ NewTTP);
return NewTTP;
}
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=295696&r1=295695&r2=295696&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Feb 21 00:30:38 2017
@@ -1121,6 +1121,23 @@ TemplateInstantiator::TransformTemplateP
return E;
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
+
+ if (TemplateArgs.getNumLevels() != TemplateArgs.getNumSubstitutedLevels()) {
+ // We're performing a partial substitution, so the substituted argument
+ // could be dependent. As a result we can't create a SubstNonType*Expr
+ // node now, since that represents a fully-substituted argument.
+ // FIXME: We should have some AST representation for this.
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ // FIXME: This won't work for alias templates.
+ assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() &&
+ "unexpected pack arguments in partial substitution");
+ Arg = Arg.pack_begin()->getPackExpansionPattern();
+ }
+ assert(Arg.getKind() == TemplateArgument::Expression &&
+ "unexpected nontype template argument kind in partial substitution");
+ return Arg.getAsExpr();
+ }
+
if (NTTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
@@ -1429,12 +1446,9 @@ TemplateInstantiator::TransformTemplateT
NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
TransformDecl(TL.getNameLoc(), OldTTPDecl));
- QualType Result
- = getSema().Context.getTemplateTypeParmType(T->getDepth()
- - TemplateArgs.getNumLevels(),
- T->getIndex(),
- T->isParameterPack(),
- NewTTPDecl);
+ QualType Result = getSema().Context.getTemplateTypeParmType(
+ T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(),
+ T->isParameterPack(), NewTTPDecl);
TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
return Result;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=295696&r1=295695&r2=295696&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Feb 21 00:30:38 2017
@@ -2074,13 +2074,10 @@ Decl *TemplateDeclInstantiator::VisitTem
// 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 = TemplateTypeParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
+ D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
Inst->setAccess(AS_public);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
@@ -2218,17 +2215,14 @@ Decl *TemplateDeclInstantiator::VisitNon
if (IsExpandedParameterPack)
Param = NonTypeTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(),
- D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
ExpandedParameterPackTypesAsWritten);
else
- Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getInnerLocStart(),
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), T,
- D->isParameterPack(), DI);
+ Param = NonTypeTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
Param->setAccess(AS_public);
if (Invalid)
@@ -2349,19 +2343,15 @@ TemplateDeclInstantiator::VisitTemplateT
// Build the template template parameter.
TemplateTemplateParmDecl *Param;
if (IsExpandedParameterPack)
- Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), InstParams,
- ExpandedParams);
+ Param = TemplateTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->getIdentifier(), InstParams, ExpandedParams);
else
- Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->isParameterPack(),
- D->getIdentifier(), InstParams);
+ Param = TemplateTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
+ D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
Modified: cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp?rev=295696&r1=295695&r2=295696&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp Tue Feb 21 00:30:38 2017
@@ -176,3 +176,29 @@ namespace default_args_from_ctor {
template <class A> struct T { template<typename B> T(A = 0, B = 0) {} };
T t(0, 0);
}
+
+namespace transform_params {
+ template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]>
+ struct A { // expected-note 2{{candidate}}
+ template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W>
+ A(U<X>, W<Y>); // expected-note {{[with V = int, M = 12, Y = &transform_params::n]}}
+
+ static constexpr T v = N;
+ };
+
+ int n[12];
+ template<int (*)[12]> struct Q {};
+ Q<&n> qn;
+ // FIXME: The class template argument deduction result here is correct, but
+ // we incorrectly fail to deduce arguments for the constructor!
+ A a(qn, qn); // expected-error {{no matching constructor for initialization of 'transform_params::A<int, 12, Q, &transform_params::n>'}}
+ static_assert(a.v == 12);
+
+ // FIXME: This causes a crash right now (not class template deduction related).
+#if 0
+ template<typename ...T> struct B {
+ template<T ...V> B(T (&...p)[V]);
+ };
+ B b({1, 2, 3}, {"foo", "bar"}, {'x', 'y', 'z', 'w'});
+#endif
+}
Modified: cfe/trunk/test/SemaTemplate/deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/deduction.cpp?rev=295696&r1=295695&r2=295696&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/deduction.cpp (original)
+++ cfe/trunk/test/SemaTemplate/deduction.cpp Tue Feb 21 00:30:38 2017
@@ -481,3 +481,16 @@ namespace check_extended_pack {
int n;
void h() { g<0>(Y<0, &n>()); } // expected-error {{no matching function}}
}
+
+namespace dependent_template_template_param_non_type_param_type {
+ template<int N> struct A { // expected-note 2{{candidate}}
+ template<typename V = int, V M = 12, V (*Y)[M], template<V (*v)[M]> class W>
+ A(W<Y>); // expected-note {{[with V = int, M = 12, Y = &dependent_template_template_param_non_type_param_type::n]}}
+ };
+
+ int n[12];
+ template<int (*)[12]> struct Q {};
+ Q<&n> qn;
+ // FIXME: This should be accepted, but we somehow fail to deduce W.
+ A<0> a(qn); // expected-error {{no matching constructor for initialization}}
+}
More information about the cfe-commits
mailing list