Author: Matheus Izvekov Date: 2021-08-03T22:39:48+02:00 New Revision: 219790c1f53665a8b5f7578472e5c2675f9bec6a
URL: https://github.com/llvm/llvm-project/commit/219790c1f53665a8b5f7578472e5c2675f9bec6a DIFF: https://github.com/llvm/llvm-project/commit/219790c1f53665a8b5f7578472e5c2675f9bec6a.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 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 07b7e61821f7..854070aee428 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7830,8 +7830,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 4c16ddc782fa..4ff2aa5307bb 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6089,9 +6089,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 @@ -6101,14 +6103,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 72b277821978..708b5cd8cb76 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 175388198324..5d26f2d2c11a 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 213496810147..593902c6b74d 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits