Skip to content

Commit 168ece2

Browse files
mizvekovtstellar
authored andcommitted
[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 <[email protected]> Reviewed By: rsmith Differential Revision: https://reviews.llvm.org/D107311 (cherry picked from commit 219790c)
1 parent 4178fa1 commit 168ece2

File tree

5 files changed

+39
-17
lines changed

5 files changed

+39
-17
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7828,8 +7828,7 @@ class Sema final {
78287828
TemplateArgumentLoc &Arg,
78297829
SmallVectorImpl<TemplateArgument> &Converted);
78307830

7831-
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
7832-
TypeSourceInfo *Arg);
7831+
bool CheckTemplateArgument(TypeSourceInfo *Arg);
78337832
ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
78347833
QualType InstantiatedParamType, Expr *Arg,
78357834
TemplateArgument &Converted,

clang/lib/AST/ASTContext.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6066,9 +6066,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
60666066
NNS->getAsNamespaceAlias()->getNamespace()
60676067
->getOriginalNamespace());
60686068

6069+
// The difference between TypeSpec and TypeSpecWithTemplate is that the
6070+
// latter will have the 'template' keyword when printed.
60696071
case NestedNameSpecifier::TypeSpec:
60706072
case NestedNameSpecifier::TypeSpecWithTemplate: {
6071-
QualType T = getCanonicalType(QualType(NNS->getAsType(), 0));
6073+
const Type *T = getCanonicalType(NNS->getAsType());
60726074

60736075
// If we have some kind of dependent-named type (e.g., "typename T::type"),
60746076
// break it apart into its prefix and identifier, then reconsititute those
@@ -6078,14 +6080,16 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
60786080
// typedef typename T::type T1;
60796081
// typedef typename T1::type T2;
60806082
if (const auto *DNT = T->getAs<DependentNameType>())
6081-
return NestedNameSpecifier::Create(*this, DNT->getQualifier(),
6082-
const_cast<IdentifierInfo *>(DNT->getIdentifier()));
6083-
6084-
// Otherwise, just canonicalize the type, and force it to be a TypeSpec.
6085-
// FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the
6086-
// first place?
6083+
return NestedNameSpecifier::Create(
6084+
*this, DNT->getQualifier(),
6085+
const_cast<IdentifierInfo *>(DNT->getIdentifier()));
6086+
if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>())
6087+
return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true,
6088+
const_cast<Type *>(T));
6089+
6090+
// TODO: Set 'Template' parameter to true for other template types.
60876091
return NestedNameSpecifier::Create(*this, nullptr, false,
6088-
const_cast<Type *>(T.getTypePtr()));
6092+
const_cast<Type *>(T));
60896093
}
60906094

60916095
case NestedNameSpecifier::Global:

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12472,6 +12472,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
1247212472
return false;
1247312473
}
1247412474

12475+
const NestedNameSpecifier *CNNS =
12476+
Context.getCanonicalNestedNameSpecifier(Qual);
1247512477
for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) {
1247612478
NamedDecl *D = *I;
1247712479

@@ -12497,8 +12499,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
1249712499
// using decls differ if they name different scopes (but note that
1249812500
// template instantiation can cause this check to trigger when it
1249912501
// didn't before instantiation).
12500-
if (Context.getCanonicalNestedNameSpecifier(Qual) !=
12501-
Context.getCanonicalNestedNameSpecifier(DQual))
12502+
if (CNNS != Context.getCanonicalNestedNameSpecifier(DQual))
1250212503
continue;
1250312504

1250412505
Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange();

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
10791079
return Param;
10801080

10811081
// Check the template argument itself.
1082-
if (CheckTemplateArgument(Param, DefaultTInfo)) {
1082+
if (CheckTemplateArgument(DefaultTInfo)) {
10831083
Param->setInvalidDecl();
10841084
return Param;
10851085
}
@@ -5042,7 +5042,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
50425042
}
50435043
}
50445044

5045-
if (CheckTemplateArgument(Param, TSI))
5045+
if (CheckTemplateArgument(TSI))
50465046
return true;
50475047

50485048
// Add the converted template type argument.
@@ -5661,7 +5661,7 @@ bool Sema::CheckTemplateArgumentList(
56615661
TemplateArgumentListInfo NewArgs = TemplateArgs;
56625662

56635663
// Make sure we get the template parameter list from the most
5664-
// recentdeclaration, since that is the only one that has is guaranteed to
5664+
// recent declaration, since that is the only one that is guaranteed to
56655665
// have all the default template argument information.
56665666
TemplateParameterList *Params =
56675667
cast<TemplateDecl>(Template->getMostRecentDecl())
@@ -6208,8 +6208,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
62086208
///
62096209
/// This routine implements the semantics of C++ [temp.arg.type]. It
62106210
/// returns true if an error occurred, and false otherwise.
6211-
bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
6212-
TypeSourceInfo *ArgInfo) {
6211+
bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
62136212
assert(ArgInfo && "invalid TypeSourceInfo");
62146213
QualType Arg = ArgInfo->getType();
62156214
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();

clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,23 @@ template <True T, Bar2 U>
8181
requires true struct S4; // expected-note {{template is declared here}}
8282
template <True T, True U>
8383
requires true struct S4<T, U>; // expected-error {{class template partial specialization is not more specialized than the primary template}}
84+
85+
struct X {
86+
template<int> struct Y {
87+
using type = int;
88+
};
89+
};
90+
91+
template<class T> concept C1 = sizeof(T) != 0;
92+
template<class T> concept C2 = C1<typename T::template Y<1>::type>;
93+
94+
template<class T> requires C1<T> void t1() = delete; // expected-note {{candidate function}}
95+
template<class T> requires C1<T> && C2<T> void t1() = delete; // expected-note {{candidate function}}
96+
template void t1<X>();
97+
void t1() { t1<X>(); } // expected-error {{call to deleted function 't1'}}
98+
99+
template<class T> requires C1<T> void t2() {}; // expected-note 2 {{candidate function}}
100+
template<class T> requires C2<T> void t2() {}; // expected-note 2 {{candidate function}}
101+
template void t2<X>(); // expected-error {{partial ordering for explicit instantiation of 't2' is ambiguous}}
102+
void t2() { t2<X>(); } // expected-error {{call to 't2' is ambiguous}}
84103
} // namespace PR47174

0 commit comments

Comments
 (0)