Skip to content

[Clang][Sema] Correctly look up primary template for variable template specializations #80359

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ Bug Fixes in This Version

- Fixed missing warnings when doing bool-like conversions in C23 (`#79435 <https://github.com/llvm/llvm-project/issues/79435>`_).

- Clang now accepts qualified partial/explicit specializations of variable templates that
are not nominable in the lookup context of the specialization.

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8456,7 +8456,7 @@ class Sema final {
SourceLocation RAngleLoc);

DeclResult ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI,
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
StorageClass SC, bool IsPartialSpecialization);

Expand Down
11 changes: 6 additions & 5 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7727,7 +7727,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
? TemplateParamLists[0]->getTemplateLoc()
: SourceLocation();
DeclResult Res = ActOnVarTemplateSpecialization(
S, D, TInfo, TemplateKWLoc, TemplateParams, SC,
S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
IsPartialSpecialization);
if (Res.isInvalid())
return nullptr;
Expand Down Expand Up @@ -8070,8 +8070,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
} else {
// If this is an explicit specialization of a static data member, check it.
if (IsMemberSpecialization && !NewVD->isInvalidDecl() &&
CheckMemberSpecialization(NewVD, Previous))
if (IsMemberSpecialization && !IsVariableTemplateSpecialization &&
!NewVD->isInvalidDecl() && CheckMemberSpecialization(NewVD, Previous))
NewVD->setInvalidDecl();

// Merge the decl with the existing one if appropriate.
Expand All @@ -8086,15 +8086,16 @@ NamedDecl *Sema::ActOnVariableDeclarator(
Previous.clear();
NewVD->setInvalidDecl();
}
} else if (D.getCXXScopeSpec().isSet()) {
} else if (D.getCXXScopeSpec().isSet() &&
!IsVariableTemplateSpecialization) {
// No previous declaration in the qualifying scope.
Diag(D.getIdentifierLoc(), diag::err_no_member)
<< Name << computeDeclContext(D.getCXXScopeSpec(), true)
<< D.getCXXScopeSpec().getRange();
NewVD->setInvalidDecl();
}

if (!IsVariableTemplateSpecialization && !IsPlaceholderVariable)
if (!IsPlaceholderVariable)
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));

// CheckVariableDeclaration will set NewVD as invalid if something is in
Expand Down
21 changes: 8 additions & 13 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4601,9 +4601,9 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
}

DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
TemplateParameterList *TemplateParams, StorageClass SC,
bool IsPartialSpecialization) {
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
StorageClass SC, bool IsPartialSpecialization) {
// D must be variable template id.
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
"Variable template specialization is declared with a template id.");
Expand Down Expand Up @@ -4783,17 +4783,12 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// Note that this is an explicit specialization.
Specialization->setSpecializationKind(TSK_ExplicitSpecialization);

if (PrevDecl) {
// Check that this isn't a redefinition of this specialization,
// merging with previous declarations.
LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName,
forRedeclarationInCurContext());
PrevSpec.addDecl(PrevDecl);
D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec));
} else if (Specialization->isStaticDataMember() &&
Specialization->isOutOfLine()) {
Previous.clear();
if (PrevDecl)
Previous.addDecl(PrevDecl);
else if (Specialization->isStaticDataMember() &&
Specialization->isOutOfLine())
Specialization->setAccess(VarTemplate->getAccess());
}

return Specialization;
}
Expand Down
112 changes: 112 additions & 0 deletions clang/test/CXX/dcl.decl/dcl.meaning/dcl.meaning.general/p3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

namespace N0 {
template<typename T>
void f0();

template<typename T>
int x0 = 0;

template<typename T>
class C0;
}
using namespace N0;

template<>
void f0<int>(); // expected-error {{no function template matches}}

template<>
int x0<int>;

template<>
class C0<int>;

namespace N1 {
namespace N2 {
template<typename T>
void f2();

template<typename T>
int x2 = 0;

template<typename T>
class C2;
}
using namespace N2;
}

template<>
void N1::f2<int>(); // expected-error {{no function template matches}}

template<>
int N1::x2<int>;

template<>
class N1::C2<int>;

namespace N3 {
namespace N4 {
template<typename T>
void f4();

template<typename T>
int x4 = 0;

template<typename T>
class C4;
}
using N4::f4;
using N4::x4;
using N4::C4;
}

template<>
void N3::f4<int>(); // expected-error {{no function template matches}}

template<>
int N3::x4<int>;

template<>
class N3::C4<int>;

inline namespace N5 {
template<typename T>
void f5();

template<typename T>
int x5 = 0;

template<typename T>
class C5;
}

template<>
void f5<int>();

template<>
int x5<int>;

template<>
class C5<int>;

namespace N6 {
inline namespace N7 {
template<typename T>
void f7();

template<typename T>
int x7 = 0;

template<typename T>
class C7;
}
}

template<>
void N6::f7<int>();

template<>
int N6::x7<int>;

template<>
class N6::C7<int>;