mizvekov created this revision. mizvekov edited the summary of this revision. mizvekov updated this revision to Diff 363710. mizvekov edited the summary of this revision. mizvekov added a comment. mizvekov updated this revision to Diff 363719. mizvekov updated this revision to Diff 363722. mizvekov published this revision for review. mizvekov added a reviewer: rsmith. mizvekov added a subscriber: Quuxplusone. Herald added a project: clang. Herald added a subscriber: cfe-commits.
. mizvekov added a comment. . mizvekov added a comment. . When canonicalizing nested name spcifiers 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> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D107311 Files: 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
Index: clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp =================================================================== --- clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp +++ clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp @@ -81,4 +81,23 @@ 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 Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -1079,7 +1079,7 @@ return Param; // Check the template argument itself. - if (CheckTemplateArgument(Param, DefaultTInfo)) { + if (CheckTemplateArgument(DefaultTInfo)) { Param->setInvalidDecl(); return Param; } @@ -5042,7 +5042,7 @@ } } - if (CheckTemplateArgument(Param, TSI)) + if (CheckTemplateArgument(TSI)) return true; // Add the converted template type argument. @@ -5661,7 +5661,7 @@ 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 @@ /// /// 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(); Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -12472,6 +12472,8 @@ 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 @@ // using decls differ if they name different 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(); Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -6089,9 +6089,11 @@ NNS->getAsNamespaceAlias()->getNamespace() ->getOriginalNamespace()); + // The difference 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 @@ // 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: Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -7823,8 +7823,7 @@ 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,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits