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