https://github.com/dty2 created https://github.com/llvm/llvm-project/pull/138122

Try to fix missing initializer for inline static template member with auto 
caused by delayed template instantiation.

Bug Fix: [Bug 135032](https://github.com/llvm/llvm-project/issues/135032)
Problem Description:
Due to nested templates, when instantiating the outer layer (the template 
class), the inner layer (the template variable) uses delayed instantiation.
This causes the declaration (VarDecl) of the template variable to retain the 
type from the original template declaration (i.e., auto), and it loses the 
initializer.
Later, when instantiating the template variable, its 
VarTemplateSpecializationDecl type depends on the VarDecl type.
Thus, the VarTemplateSpecializationDecl also has no initializer, and its type 
remains auto.
Ultimately, when building the reference expression in 
Sema::BuildDeclarationNameExpr, the expression's type is auto and stays as auto 
until code generation, triggering llvm_unreachable in CodeGenTypes::ConvertType.

Reproduction Steps:
Test Code:
``` cxx
template <typename T> struct B {
  template <typename G> inline static auto var = 5;
};

int main() {
  int bb = B<int>::var<int>;
  return 0;
}
```
GDB Breakpoints for Debugging:
Annotations like #(1) mark the call order in a tree structure. For example, two 
#(3) entries mean Sema::CheckVarTemplateId calls Sema::BuildDeclarationNameExpr 
after its own execution.
``` gdb
#(1)
b Sema::BuildTemplateIdExpr
#(2)
b Sema::CheckVarTemplateId
#(3)
b Sema::CheckVarTemplateId
#(4)
b Sema::BuildVarTemplateInstantiation
#(5)
b TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl
#(6)
b VarTemplateSpecializationDecl::Create
#(7)
b VarTemplateSpecializationDecl::VarTemplateSpecializationDecl
#(8)
b VarDecl::VarDecl
#(6)
b Sema::BuildVariableInstantiation
#(7)
b Sema::InstantiateVariableInitializer
#(3)
b Sema::BuildDeclarationNameExpr
#(4)
b Sema::BuildDeclRefExpr
```
Key Observations:
While debugging, I generated the AST for the test code and noticed a 
contradiction:

The AST shows VarTemplateSpecializationDecl as int (correct), but GDB reveals 
its type is actually auto during execution.

Example from AST:

DeclRefExpr 0x598f651f5a60 <col:9, col:27> 'auto' lvalue 
VarTemplateSpecialization 0x598f651f5980 'var' 'int' (VarTemplate 
0x598f651d1938 'var')
The DeclRefExpr has type auto, while its referenced VarTemplateSpecialization 
claims to be int—a clear inconsistency.

Solution:
Since I noticed that the deduction of auto type is caused by the initializer
I plan to do special processing for template variables of type auto, that is, 
to prevent their delayed instantiation
so that their initializers will not be lost when the outer template class is 
instantiated

From f9bdf07f09d7a04c190ae4d77c4983d4b7fa4936 Mon Sep 17 00:00:00 2001
From: hunter <284050...@qq.com>
Date: Thu, 1 May 2025 18:52:34 +0800
Subject: [PATCH] [clang] Fix missing initializer for inline static template
 member with auto caused by delayed template instantiation.

---
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp     | 8 +++++++-
 clang/test/CodeGenCXX/cxx1z-inline-variables.cpp   | 8 ++++++++
 clang/test/SemaTemplate/cxx17-inline-variables.cpp | 6 ++++++
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 76c055d28f091..eb66ec34a956f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6027,8 +6027,14 @@ void Sema::BuildVariableInstantiation(
   Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
   Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
 
+  bool VarTemplateWithAutoType = false;
+  QualType VarSourceType = OldVar->getTypeSourceInfo()->getType();
+  if (VarSourceType->getAs<AutoType>()) {
+    VarTemplateWithAutoType = true;
+  }
+
   // Figure out whether to eagerly instantiate the initializer.
-  if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
+  if ((InstantiatingVarTemplate && !VarTemplateWithAutoType) || 
InstantiatingVarTemplatePartialSpec) {
     // 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.
diff --git a/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp 
b/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp
index 812e438f30c9a..b1d8e376b826f 100644
--- a/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp
+++ b/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp
@@ -1,5 +1,13 @@
 // RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple x86_64-linux-gnu | 
FileCheck %s
 
+template <typename T> struct B {
+  template <typename G> inline static auto var = 5;
+};
+
+int inlinevartemplate = B<int>::var<int>;
+// CHECK: @_ZN1BIiE3varIiEE = {{.*}}global i32 5{{.*}}comdat
+// CHECK-NOT: @_ZN1BIiE3varIfEE
+
 struct Q {
   // CHECK: @_ZN1Q1kE = linkonce_odr constant i32 5, comdat
   static constexpr int k = 5;
diff --git a/clang/test/SemaTemplate/cxx17-inline-variables.cpp 
b/clang/test/SemaTemplate/cxx17-inline-variables.cpp
index 7fc0aa8eeeb0c..27067c8e1b5e4 100644
--- a/clang/test/SemaTemplate/cxx17-inline-variables.cpp
+++ b/clang/test/SemaTemplate/cxx17-inline-variables.cpp
@@ -27,3 +27,9 @@ template <typename T> constexpr int A<T>::n = sizeof(A) + 
sizeof(T);
 template <typename T> inline constexpr int A<T>::m = sizeof(A) + sizeof(T);
 static_assert(A<int>().f() == 5);
 static_assert(A<int>().g() == 5);
+
+template <typename T> struct B {
+  template <typename G> inline static auto var = 5;
+};
+
+int b = B<int>::var<int>;

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to