Author: Matheus Izvekov Date: 2021-08-10T23:12:57-07:00 New Revision: 168ece289bd4266b711f9bbccc0fe52eb772700c
URL: https://github.com/llvm/llvm-project/commit/168ece289bd4266b711f9bbccc0fe52eb772700c DIFF: https://github.com/llvm/llvm-project/commit/168ece289bd4266b711f9bbccc0fe52eb772700c.diff LOG: [clang] fix canonicalization of nested name specifiers See PR47174. When canonicalizing nested name specifiers of the type kind, the prefix for 'DependentTemplateSpecialization' types was being dropped, leading to malformed types which would cause failures when rebuilding template names. Signed-off-by: Matheus Izvekov <mizve...@gmail.com> Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D107311 (cherry picked from commit 219790c1f53665a8b5f7578472e5c2675f9bec6a) Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/AST/ASTContext.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaTemplate.cpp clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 83a2d132bf6a4..d8b2546b81a34 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7828,8 +7828,7 @@ class Sema final { TemplateArgumentLoc &Arg, SmallVectorImpl<TemplateArgument> &Converted); - bool CheckTemplateArgument(TemplateTypeParmDecl *Param, - TypeSourceInfo *Arg); + bool CheckTemplateArgument(TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e102a3ba508d4..fdba204fbe7ff 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6066,9 +6066,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { NNS->getAsNamespaceAlias()->getNamespace() ->getOriginalNamespace()); + // The diff erence between TypeSpec and TypeSpecWithTemplate is that the + // latter will have the 'template' keyword when printed. case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); + const Type *T = getCanonicalType(NNS->getAsType()); // If we have some kind of dependent-named type (e.g., "typename T::type"), // break it apart into its prefix and identifier, then reconsititute those @@ -6078,14 +6080,16 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { // typedef typename T::type T1; // typedef typename T1::type T2; if (const auto *DNT = T->getAs<DependentNameType>()) - return NestedNameSpecifier::Create(*this, DNT->getQualifier(), - const_cast<IdentifierInfo *>(DNT->getIdentifier())); - - // Otherwise, just canonicalize the type, and force it to be a TypeSpec. - // FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the - // first place? + return NestedNameSpecifier::Create( + *this, DNT->getQualifier(), + const_cast<IdentifierInfo *>(DNT->getIdentifier())); + if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>()) + return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, + const_cast<Type *>(T)); + + // TODO: Set 'Template' parameter to true for other template types. return NestedNameSpecifier::Create(*this, nullptr, false, - const_cast<Type *>(T.getTypePtr())); + const_cast<Type *>(T)); } case NestedNameSpecifier::Global: diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 83c97626ff7e7..da4f4f8620955 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12472,6 +12472,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, return false; } + const NestedNameSpecifier *CNNS = + Context.getCanonicalNestedNameSpecifier(Qual); for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { NamedDecl *D = *I; @@ -12497,8 +12499,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // using decls diff er if they name diff erent scopes (but note that // template instantiation can cause this check to trigger when it // didn't before instantiation). - if (Context.getCanonicalNestedNameSpecifier(Qual) != - Context.getCanonicalNestedNameSpecifier(DQual)) + if (CNNS != Context.getCanonicalNestedNameSpecifier(DQual)) continue; Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1753881983241..5d26f2d2c11a5 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1079,7 +1079,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; // Check the template argument itself. - if (CheckTemplateArgument(Param, DefaultTInfo)) { + if (CheckTemplateArgument(DefaultTInfo)) { Param->setInvalidDecl(); return Param; } @@ -5042,7 +5042,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, } } - if (CheckTemplateArgument(Param, TSI)) + if (CheckTemplateArgument(TSI)) return true; // Add the converted template type argument. @@ -5661,7 +5661,7 @@ bool Sema::CheckTemplateArgumentList( TemplateArgumentListInfo NewArgs = TemplateArgs; // Make sure we get the template parameter list from the most - // recentdeclaration, since that is the only one that has is guaranteed to + // recent declaration, since that is the only one that is guaranteed to // have all the default template argument information. TemplateParameterList *Params = cast<TemplateDecl>(Template->getMostRecentDecl()) @@ -6208,8 +6208,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( /// /// This routine implements the semantics of C++ [temp.arg.type]. It /// returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, - TypeSourceInfo *ArgInfo) { +bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) { assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp index 2134968101470..593902c6b74d9 100644 --- a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp +++ b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp @@ -81,4 +81,23 @@ template <True T, Bar2 U> requires true struct S4; // expected-note {{template is declared here}} template <True T, True U> requires true struct S4<T, U>; // expected-error {{class template partial specialization is not more specialized than the primary template}} + +struct X { + template<int> struct Y { + using type = int; + }; +}; + +template<class T> concept C1 = sizeof(T) != 0; +template<class T> concept C2 = C1<typename T::template Y<1>::type>; + +template<class T> requires C1<T> void t1() = delete; // expected-note {{candidate function}} +template<class T> requires C1<T> && C2<T> void t1() = delete; // expected-note {{candidate function}} +template void t1<X>(); +void t1() { t1<X>(); } // expected-error {{call to deleted function 't1'}} + +template<class T> requires C1<T> void t2() {}; // expected-note 2 {{candidate function}} +template<class T> requires C2<T> void t2() {}; // expected-note 2 {{candidate function}} +template void t2<X>(); // expected-error {{partial ordering for explicit instantiation of 't2' is ambiguous}} +void t2() { t2<X>(); } // expected-error {{call to 't2' is ambiguous}} } // namespace PR47174 _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits