https://github.com/akash-manna-sky updated 
https://github.com/llvm/llvm-project/pull/217709

>From cb00d11cb959de73ecdb282b5ab3502f0cf10da2 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Thu, 20 Aug 2026 23:05:31 +0530
Subject: [PATCH 1/2] [clang] Fix bogus "deduced type depends on itself" for
 variable template specializations

A variable template specialization with a deduced type first named in a
context that doesn't require its definition (e.g. decltype(obj<0>)) can
be left with an undeduced type: for a member variable template of a
class template the initializer lives on the in-class pattern, and
DoMarkVarDeclReferenced never instantiated the definition because its
undeduced-type clause excluded constexpr variables. On a later
reference, CheckVarTemplateId found the existing undeduced
specialization and wrongly assumed it was substituting its own
initializer, rejecting valid code.

Emit the error only when the specialization's initializer instantiation
is really in progress (tracked via InstantiatingSpecializations), make
the eager initializer instantiation in BuildVariableInstantiation
register a RecursiveInstGuard so genuine (also indirect) cycles are
still caught, and drop the !UsableInConstantExpr restriction so any
reference to an undeduced specialization instantiates its definition,
matching GCC for decltype.

Fixes #214477
---
 clang/docs/ReleaseNotes.md                    |  5 ++
 clang/lib/Sema/SemaExpr.cpp                   |  3 +-
 clang/lib/Sema/SemaTemplate.cpp               | 15 +++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  2 +
 clang/test/SemaTemplate/GH214477.cpp          | 76 +++++++++++++++++++
 5 files changed, 95 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/SemaTemplate/GH214477.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 8c9467ca7b742..0ac80a68f46ef 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -528,6 +528,11 @@ features cannot lower the translation-unit ABI level;
   parameter that follows a parameter pack (e.g.
   `template <typename... T> S::S(T..., int = 10) {}`).  (#GH216211)
 
+- Fixed a bogus "deduced type depends on itself" error when a variable template
+  specialization with a deduced type was first named in a context that did not
+  require its definition (such as ``decltype``) and then referenced again;
+  Clang now instantiates the definition to deduce the type instead. (#GH214477)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index da76bbf3c35f0..a5a7398aee15f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -20715,8 +20715,7 @@ static void DoMarkVarDeclReferenced(
 
   bool NeedDefinition =
       OdrUse == OdrUseContext::Used || NeededForConstantEvaluation ||
-      (TSK != clang::TSK_Undeclared && !UsableInConstantExpr &&
-       Var->getType()->isUndeducedType());
+      (TSK != clang::TSK_Undeclared && Var->getType()->isUndeducedType());
 
   assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
          "Can't instantiate a partial template specialization.");
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 1fde412749cc9..ac7c789fe74e6 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4658,18 +4658,25 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, 
SourceLocation TemplateLoc,
           Template->findSpecialization(CTAI.CanonicalConverted, InsertPos)) {
     checkSpecializationReachability(TemplateNameLoc, Spec);
     if (Spec->getType()->isUndeducedType()) {
-      if (ParsingInitForAutoVars.count(Spec))
+      if (ParsingInitForAutoVars.count(Spec)) {
         Diag(TemplateNameLoc,
              diag::err_auto_variable_cannot_appear_in_own_initializer)
             << diag::ParsingInitFor::VarTemplateExplicitSpec << Spec
             << Spec->getType();
-      else
+        return true;
+      }
+      if (InstantiatingSpecializations.contains(
+              {Spec->getCanonicalDecl(),
+               unsigned(RecursiveInstGuard::Kind::Template)})) {
         // We are substituting the initializer of this variable template
         // specialization.
         Diag(TemplateNameLoc, diag::err_var_template_spec_type_depends_on_self)
             << Spec << Spec->getType();
-
-      return true;
+        return true;
+      }
+      // Otherwise, the specialization was declared at a point where its type
+      // was not needed, so its initializer has not been instantiated yet; the
+      // type will be deduced when the definition is instantiated.
     }
     // If we already have a variable template specialization, return it.
     return Spec;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ff29ae27a3b66..fab93559a3f6c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6523,6 +6523,8 @@ void Sema::BuildVariableInstantiation(
     // We're producing a template. Don't instantiate the initializer yet.
   } else if (NewVar->getType()->isUndeducedType()) {
     // We need the type to complete the declaration of the variable.
+    RecursiveInstGuard AlreadyInstantiating(*this, NewVar,
+                                            
RecursiveInstGuard::Kind::Template);
     InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
   } else if (InstantiatingSpecFromTemplate ||
              (OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
diff --git a/clang/test/SemaTemplate/GH214477.cpp 
b/clang/test/SemaTemplate/GH214477.cpp
new file mode 100644
index 0000000000000..76f8e9a2c51e8
--- /dev/null
+++ b/clang/test/SemaTemplate/GH214477.cpp
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++26 -verify %s
+
+namespace GH214477 {
+
+struct dummy {};
+template <typename A> struct real { A a; };
+
+template <typename V> struct Tests {
+  template <int> static constexpr dummy obj = {};
+
+  const int reg = [] {
+    using X = decltype(obj<0>);
+    static_assert(__is_same(X, const real<int>));
+    (void)&obj<0>;
+    return 0;
+  }();
+
+  template <int Tmp>
+    requires(Tmp == 0)
+  static constexpr real obj<Tmp> = {0};
+};
+
+void test() { (void)Tests<int>{}; }
+
+template <typename V> struct Tests2 {
+  template <int> static constexpr dummy obj = {};
+
+  void f() {
+    using X = decltype(obj<0>);
+    static_assert(__is_same(X, const real<int>));
+    (void)&obj<0>;
+  }
+
+  template <int Tmp>
+    requires(Tmp == 0)
+  static constexpr real obj<Tmp> = {0};
+};
+
+void test2() { Tests2<int>{}.f(); }
+
+template <typename V> struct Tests3 {
+  template <int> static constexpr dummy obj = {};
+
+  const int reg = [] {
+    (void)&obj<0>;
+    using X = decltype(obj<0>);
+    static_assert(__is_same(X, const real<int>));
+    return 0;
+  }();
+
+  template <int Tmp>
+    requires(Tmp == 0)
+  static constexpr real obj<Tmp> = {0};
+};
+
+void test3() { (void)Tests3<int>{}; }
+
+} // namespace GH214477
+
+namespace deduced_type_cycle {
+
+template <int> constexpr auto a = 0;
+template <int> constexpr auto b = 0;
+
+template <int N>
+  requires(N == 0)
+constexpr auto a<N> = b<N>; // expected-note {{in instantiation of variable 
template specialization 'deduced_type_cycle::b<N>' requested here}}
+
+template <int N>
+  requires(N == 0)
+constexpr auto b<N> = a<N>; // expected-error {{the type of variable template 
specialization 'a<0>' declared with deduced type 'const auto' depends on 
itself}}
+
+auto y = a<0>; // expected-note {{in instantiation of variable template 
specialization 'deduced_type_cycle::a<N>' requested here}}
+
+} // namespace deduced_type_cycle

>From 34b9e3302aaa6585746aa9d48de9f55da5e8c95b Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Fri, 21 Aug 2026 09:14:09 +0530
Subject: [PATCH 2/2] [clang] Simplify comment in SemaTemplate.cpp regarding
 variable template specialization instantiation

---
 clang/lib/Sema/SemaTemplate.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ac7c789fe74e6..9b844a8da1403 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4674,9 +4674,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, 
SourceLocation TemplateLoc,
             << Spec << Spec->getType();
         return true;
       }
-      // Otherwise, the specialization was declared at a point where its type
-      // was not needed, so its initializer has not been instantiated yet; the
-      // type will be deduced when the definition is instantiated.
+      // Not yet deduced; the type is completed when the definition is
+      // instantiated.
     }
     // If we already have a variable template specialization, return it.
     return Spec;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to