[llvm-branch-commits] [clang] release/23.x: Create a Template member to be the MemberSpec of a failed TemplVarDecl (#209604) (PR #209823)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jul 15 09:54:21 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: llvmbot
<details>
<summary>Changes</summary>
Backport 2c2e43675910603bab1b163655786e4850569d74
Requested by: @<!-- -->erichkeane
---
Full diff: https://github.com/llvm/llvm-project/pull/209823.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaDecl.cpp (+15)
- (modified) clang/test/SemaTemplate/class-template-spec.cpp (+21)
``````````diff
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7e1b23c971a9c..c5920f03ed6e1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -8374,6 +8374,21 @@ NamedDecl *Sema::ActOnVariableDeclarator(
<< Name << computeDeclContext(D.getCXXScopeSpec(), true)
<< D.getCXXScopeSpec().getRange();
NewVD->setInvalidDecl();
+
+ // if this is a member specialization, we don't have any primary template
+ // to be instantiated from. We set ourselves to a 'fake' clone of this so
+ // that anything that attempts to refer to this invalid declaration can
+ // act as if there IS a primary instantiation.
+ if (NewTemplate && IsMemberSpecialization) {
+ VarDecl *FakeVD =
+ VarDecl::Create(Context, DC, D.getBeginLoc(), D.getIdentifierLoc(),
+ II, R, TInfo, SC);
+ FakeVD->setInvalidDecl();
+ VarTemplateDecl *FakeInstantiatedFrom = VarTemplateDecl::Create(
+ Context, DC, D.getIdentifierLoc(), Name, TemplateParams, FakeVD);
+ FakeInstantiatedFrom->setInvalidDecl();
+ NewTemplate->setInstantiatedFromMemberTemplate(FakeInstantiatedFrom);
+ }
}
if (!IsPlaceholderVariable)
diff --git a/clang/test/SemaTemplate/class-template-spec.cpp b/clang/test/SemaTemplate/class-template-spec.cpp
index e2486f912e2c4..e60763feb2e1f 100644
--- a/clang/test/SemaTemplate/class-template-spec.cpp
+++ b/clang/test/SemaTemplate/class-template-spec.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-linux-gnu -verify=expected,cxx14 -std=c++14 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s
template<typename T, typename U = int> struct A; // expected-note {{template is declared here}} \
@@ -251,4 +252,24 @@ namespace VarTemplateMismatch {
template<> template<int> const int A<short>::x = 0;
// expected-error at -1 {{template non-type parameter has a different type 'int' in template redeclaration}}
} // namespace VarTemplateMismatch
+
+namespace VarTemplateNoMember {
+ template<typename T> struct S {};
+ // expected-error at +1{{no member named 'foo' in 'VarTemplateNoMember::S<long>'}}
+ template<> template<typename U> constexpr int S<long>::foo;
+ // In C++14, these are definitions, not declarations, so they get a
+ // redefinition error.
+ // cxx14-error at +2{{redefinition of 'foo'}}
+ // cxx14-note at -4{{previous definition is here}}
+ template<> template<typename U> constexpr int S<long>::foo;
+ // cxx14-error at +2{{redefinition of 'foo'}}
+ // cxx14-note at -2{{previous definition is here}}
+ template<> template<typename U> constexpr int S<long>::foo;
+ // cxx14-error at +2{{redefinition of 'foo'}}
+ // cxx14-note at -2{{previous definition is here}}
+ template<> template<typename U> constexpr int S<long>::foo;
+ // cxx14-error at +2{{redefinition of 'foo'}}
+ // cxx14-note at -2{{previous definition is here}}
+ template<> template<typename U> constexpr int S<long>::foo;
+} // namespace VarTemplateNoMember
#endif
``````````
</details>
https://github.com/llvm/llvm-project/pull/209823
More information about the llvm-branch-commits
mailing list