From 15361a21e01026e74cb17011b702c7d1c881ae94 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Dec 2016 06:27:18 +0000 Subject: [PATCH] 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 --- clang/include/clang/Sema/Sema.h | 3 ++ clang/lib/Sema/SemaTemplate.cpp | 31 ++++++++++++++----- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 26 ++++++++-------- clang/lib/Sema/SemaType.cpp | 9 +----- .../SemaTemplate/temp_arg_nontype_cxx1z.cpp | 21 +++++++++++++ 5 files changed, 61 insertions(+), 29 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c9f6d61b85f4..10a55539960a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 996a8baee1db..55421a3e0b03 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8e671ad46cfd..7328dcb8760f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index aa3887962d1e..ae9a3ee790e1 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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; diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index 15fd9b1f6bd5..c1fcedd58d13 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -307,3 +307,24 @@ namespace Auto { static_assert(nth_element_v<2, value_list<'a', 27U, false>> == false, "value mismatch"); } } + +namespace Nested { + template struct A { + template struct B; + template struct B

; + template struct B

{ using pointee = decltype(+**P); }; + template struct B

{ using param = T; }; + template struct B

{ using param2 = U; }; + }; + + using Int = int; + + int *n; + using Int = A::B<&n>::pointee; + + void f(int); + using Int = A::B<&f>::param; + + void g(int, int); + using Int = A::B<&g>::param2; +}