Skip to content

Commit 709c835

Browse files
erichkeanegithub-actions[bot]
authored andcommitted
Automerge: Create a Template member to be the MemberSpec of a failed TemplVarDecl (#209604)
Patch #200092 changed to no longer check the previous var template when setting whether the current one is a member specialization. However, if the previous one was actually an error case (see the example here and in the report), we ended up trying to do that anyway, which caused an assertion. This patch puts in a 'fake' declaration for the not-found declaration after we emit the 'not found' error for the purposes of allowing our diagnostics to continue evaluating these without causing problems. Fixes: #209432 (cherry picked from commit 2c2e436)
2 parents 6f37d36 + ce6af70 commit 709c835

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

clang/lib/Sema/SemaDecl.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8374,6 +8374,21 @@ NamedDecl *Sema::ActOnVariableDeclarator(
83748374
<< Name << computeDeclContext(D.getCXXScopeSpec(), true)
83758375
<< D.getCXXScopeSpec().getRange();
83768376
NewVD->setInvalidDecl();
8377+
8378+
// if this is a member specialization, we don't have any primary template
8379+
// to be instantiated from. We set ourselves to a 'fake' clone of this so
8380+
// that anything that attempts to refer to this invalid declaration can
8381+
// act as if there IS a primary instantiation.
8382+
if (NewTemplate && IsMemberSpecialization) {
8383+
VarDecl *FakeVD =
8384+
VarDecl::Create(Context, DC, D.getBeginLoc(), D.getIdentifierLoc(),
8385+
II, R, TInfo, SC);
8386+
FakeVD->setInvalidDecl();
8387+
VarTemplateDecl *FakeInstantiatedFrom = VarTemplateDecl::Create(
8388+
Context, DC, D.getIdentifierLoc(), Name, TemplateParams, FakeVD);
8389+
FakeInstantiatedFrom->setInvalidDecl();
8390+
NewTemplate->setInstantiatedFromMemberTemplate(FakeInstantiatedFrom);
8391+
}
83778392
}
83788393

83798394
if (!IsPlaceholderVariable)

clang/test/SemaTemplate/class-template-spec.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
22
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
33
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
4+
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-linux-gnu -verify=expected,cxx14 -std=c++14 %s
45
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s
56

67
template<typename T, typename U = int> struct A; // expected-note {{template is declared here}} \
@@ -251,4 +252,24 @@ namespace VarTemplateMismatch {
251252
template<> template<int> const int A<short>::x = 0;
252253
// expected-error@-1 {{template non-type parameter has a different type 'int' in template redeclaration}}
253254
} // namespace VarTemplateMismatch
255+
256+
namespace VarTemplateNoMember {
257+
template<typename T> struct S {};
258+
// expected-error@+1{{no member named 'foo' in 'VarTemplateNoMember::S<long>'}}
259+
template<> template<typename U> constexpr int S<long>::foo;
260+
// In C++14, these are definitions, not declarations, so they get a
261+
// redefinition error.
262+
// cxx14-error@+2{{redefinition of 'foo'}}
263+
// cxx14-note@-4{{previous definition is here}}
264+
template<> template<typename U> constexpr int S<long>::foo;
265+
// cxx14-error@+2{{redefinition of 'foo'}}
266+
// cxx14-note@-2{{previous definition is here}}
267+
template<> template<typename U> constexpr int S<long>::foo;
268+
// cxx14-error@+2{{redefinition of 'foo'}}
269+
// cxx14-note@-2{{previous definition is here}}
270+
template<> template<typename U> constexpr int S<long>::foo;
271+
// cxx14-error@+2{{redefinition of 'foo'}}
272+
// cxx14-note@-2{{previous definition is here}}
273+
template<> template<typename U> constexpr int S<long>::foo;
274+
} // namespace VarTemplateNoMember
254275
#endif

0 commit comments

Comments
 (0)