forked from OSchip/llvm-project
Mark 'auto' as dependent when instantiating the type of a non-type template
parameter. Fixes failed deduction for 'auto' non-type template parameters nested within templates. llvm-svn: 290660
This commit is contained in:
parent
873c275caa
commit
15361a21e0
|
@ -5790,7 +5790,10 @@ public:
|
|||
SourceLocation EqualLoc,
|
||||
ParsedType DefaultArg);
|
||||
|
||||
QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
|
||||
SourceLocation Loc);
|
||||
QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
|
||||
|
||||
Decl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
|
||||
unsigned Depth,
|
||||
unsigned Position,
|
||||
|
|
|
@ -729,8 +729,22 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
|
|||
///
|
||||
/// \returns the (possibly-promoted) parameter type if valid;
|
||||
/// otherwise, produces a diagnostic and returns a NULL type.
|
||||
QualType
|
||||
Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
|
||||
QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
|
||||
SourceLocation Loc) {
|
||||
if (TSI->getType()->isUndeducedType()) {
|
||||
// C++1z [temp.dep.expr]p3:
|
||||
// An id-expression is type-dependent if it contains
|
||||
// - an identifier associated by name lookup with a non-type
|
||||
// template-parameter declared with a type that contains a
|
||||
// placeholder type (7.1.7.4),
|
||||
TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy);
|
||||
}
|
||||
|
||||
return CheckNonTypeTemplateParameterType(TSI->getType(), Loc);
|
||||
}
|
||||
|
||||
QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
|
||||
SourceLocation Loc) {
|
||||
// We don't allow variably-modified types as the type of non-type template
|
||||
// parameters.
|
||||
if (T->isVariablyModifiedType()) {
|
||||
|
@ -759,10 +773,6 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) {
|
|||
T->isDependentType() ||
|
||||
// Allow use of auto in template parameter declarations.
|
||||
T->isUndeducedType()) {
|
||||
if (T->isUndeducedType()) {
|
||||
Diag(Loc, diag::warn_cxx14_compat_template_nontype_parm_auto_type)
|
||||
<< QualType(T->getContainedAutoType(), 0);
|
||||
}
|
||||
// C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
|
||||
// are ignored when determining its type.
|
||||
return T.getUnqualifiedType();
|
||||
|
@ -788,13 +798,18 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
|
|||
SourceLocation EqualLoc,
|
||||
Expr *Default) {
|
||||
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
|
||||
QualType T = TInfo->getType();
|
||||
|
||||
if (TInfo->getType()->isUndeducedType()) {
|
||||
Diag(D.getIdentifierLoc(),
|
||||
diag::warn_cxx14_compat_template_nontype_parm_auto_type)
|
||||
<< QualType(TInfo->getType()->getContainedAutoType(), 0);
|
||||
}
|
||||
|
||||
assert(S->isTemplateParamScope() &&
|
||||
"Non-type template parameter not in template parameter scope!");
|
||||
bool Invalid = false;
|
||||
|
||||
T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc());
|
||||
QualType T = CheckNonTypeTemplateParameterType(TInfo, D.getIdentifierLoc());
|
||||
if (T.isNull()) {
|
||||
T = Context.IntTy; // Recover with an 'int' type.
|
||||
Invalid = true;
|
||||
|
|
|
@ -2085,18 +2085,18 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
|||
ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes());
|
||||
ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes());
|
||||
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
|
||||
TypeSourceInfo *NewDI =SemaRef.SubstType(D->getExpansionTypeSourceInfo(I),
|
||||
TemplateArgs,
|
||||
D->getLocation(),
|
||||
D->getDeclName());
|
||||
TypeSourceInfo *NewDI =
|
||||
SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), TemplateArgs,
|
||||
D->getLocation(), D->getDeclName());
|
||||
if (!NewDI)
|
||||
return nullptr;
|
||||
|
||||
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
|
||||
QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(),
|
||||
D->getLocation());
|
||||
QualType NewT =
|
||||
SemaRef.CheckNonTypeTemplateParameterType(NewDI, D->getLocation());
|
||||
if (NewT.isNull())
|
||||
return nullptr;
|
||||
|
||||
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
|
||||
ExpandedParameterPackTypes.push_back(NewT);
|
||||
}
|
||||
|
||||
|
@ -2136,12 +2136,12 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
|||
if (!NewDI)
|
||||
return nullptr;
|
||||
|
||||
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
|
||||
QualType NewT = SemaRef.CheckNonTypeTemplateParameterType(
|
||||
NewDI->getType(),
|
||||
D->getLocation());
|
||||
QualType NewT =
|
||||
SemaRef.CheckNonTypeTemplateParameterType(NewDI, D->getLocation());
|
||||
if (NewT.isNull())
|
||||
return nullptr;
|
||||
|
||||
ExpandedParameterPackTypesAsWritten.push_back(NewDI);
|
||||
ExpandedParameterPackTypes.push_back(NewT);
|
||||
}
|
||||
|
||||
|
@ -2161,6 +2161,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
|||
if (!NewPattern)
|
||||
return nullptr;
|
||||
|
||||
SemaRef.CheckNonTypeTemplateParameterType(NewPattern, D->getLocation());
|
||||
DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(),
|
||||
NumExpansions);
|
||||
if (!DI)
|
||||
|
@ -2176,8 +2177,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
|||
return nullptr;
|
||||
|
||||
// Check that this type is acceptable for a non-type template parameter.
|
||||
T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(),
|
||||
D->getLocation());
|
||||
T = SemaRef.CheckNonTypeTemplateParameterType(DI, D->getLocation());
|
||||
if (T.isNull()) {
|
||||
T = SemaRef.Context.IntTy;
|
||||
Invalid = true;
|
||||
|
|
|
@ -1534,14 +1534,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
|||
// template type parameter.
|
||||
Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0);
|
||||
} else {
|
||||
// If auto appears in the declaration of a template parameter, treat
|
||||
// the parameter as type-dependent.
|
||||
bool IsDependent =
|
||||
S.getLangOpts().CPlusPlus1z &&
|
||||
declarator.getContext() == Declarator::TemplateParamContext;
|
||||
Result = Context.getAutoType(QualType(),
|
||||
AutoTypeKeyword::Auto,
|
||||
IsDependent);
|
||||
Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -307,3 +307,24 @@ namespace Auto {
|
|||
static_assert(nth_element_v<2, value_list<'a', 27U, false>> == false, "value mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
namespace Nested {
|
||||
template<typename T> struct A {
|
||||
template<auto X> struct B;
|
||||
template<auto *P> struct B<P>;
|
||||
template<auto **P> struct B<P> { using pointee = decltype(+**P); };
|
||||
template<auto (*P)(T)> struct B<P> { using param = T; };
|
||||
template<typename U, auto (*P)(T, U)> struct B<P> { using param2 = U; };
|
||||
};
|
||||
|
||||
using Int = int;
|
||||
|
||||
int *n;
|
||||
using Int = A<int>::B<&n>::pointee;
|
||||
|
||||
void f(int);
|
||||
using Int = A<int>::B<&f>::param;
|
||||
|
||||
void g(int, int);
|
||||
using Int = A<int>::B<&g>::param2;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue