forked from OSchip/llvm-project
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.) llvm-svn: 295696
This commit is contained in:
parent
16d9730b86
commit
b4f9625a7b
|
@ -1479,6 +1479,7 @@ public:
|
|||
unsigned NumExpansions);
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::setDepth;
|
||||
using TemplateParmPosition::getPosition;
|
||||
using TemplateParmPosition::setPosition;
|
||||
using TemplateParmPosition::getIndex;
|
||||
|
|
|
@ -47,6 +47,10 @@ namespace clang {
|
|||
/// 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.
|
||||
MultiLevelTemplateArgumentList() { }
|
||||
|
@ -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();
|
||||
|
|
|
@ -1442,6 +1442,8 @@ struct ConvertConstructorToDeductionGuideTransform {
|
|||
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 ConvertConstructorToDeductionGuideTransform {
|
|||
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 ConvertConstructorToDeductionGuideTransform {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1121,6 +1121,23 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
|
|||
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::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
|
|||
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;
|
||||
|
|
|
@ -2074,13 +2074,10 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
|
|||
// 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::VisitNonTypeTemplateParmDecl(
|
|||
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::VisitTemplateTemplateParmDecl(
|
|||
// 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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue