From 43feab8221e1df82e08a93cd7cd8e6850297c32a Mon Sep 17 00:00:00 2001 From: Younan Zhang Date: Thu, 22 May 2025 13:30:45 +0800 Subject: [PATCH] [Clang] Do not defer variable template instantiation for undeduced types The previous approach broke the instantiation convention for templated substitutions, as we were attempting to instantiate the initializer even when it was still dependent. We deferred variable template instantiation until the end of the TU. However, type deduction requires the initializer immediately, similar to how constant evaluation does. --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Sema/SemaExpr.cpp | 3 +- .../CodeGenCXX/cxx1z-inline-variables.cpp | 14 ++++++ .../SemaTemplate/cxx17-inline-variables.cpp | 44 ++++++++++++++++++- 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 95f5d055b08ed..8bd6e924fca37 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -743,6 +743,7 @@ Bug Fixes to C++ Support in a ``constexpr`` function. (#GH131432) - Fixed an incorrect TreeTransform for calls to ``consteval`` functions if a conversion template is present. (#GH137885) - Clang now emits a warning when class template argument deduction for alias templates is used in C++17. (#GH133806) +- Fixed a missed initializer instantiation bug for variable templates. (#GH134526), (#GH138122) - Fix a crash when checking the template template parameters of a dependent lambda appearing in an alias declaration. (#GH136432), (#GH137014), (#GH138018) - Fixed an assertion when trying to constant-fold various builtins when the argument diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 414a986dd6196..452dbbfe23c5b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -20158,9 +20158,10 @@ static void DoMarkVarDeclReferenced( Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); } - if (UsableInConstantExpr) { + if (UsableInConstantExpr || Var->getType()->isUndeducedType()) { // Do not defer instantiations of variables that could be used in a // constant expression. + // The type deduction also needs a complete initializer. SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] { SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); }); diff --git a/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp b/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp index 812e438f30c9a..9b1a6e4647e85 100644 --- a/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp +++ b/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp @@ -1,5 +1,19 @@ // RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s +template struct InlineAuto { + template inline static auto var = 5; +}; +int inlineauto = InlineAuto::var; +// CHECK: @_ZN10InlineAutoIiE3varIiEE = {{.*}}i32 5{{.*}}comdat + +template struct PartialInlineAuto { + template inline static auto var = 6; + template inline static auto var = 7; +}; + +int partialinlineauto = PartialInlineAuto::var; +// CHECK: @_ZN17PartialInlineAutoIiE3varIiiEE = {{.*}}i32 7{{.*}}comdat + 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..d51588bd492ee 100644 --- a/clang/test/SemaTemplate/cxx17-inline-variables.cpp +++ b/clang/test/SemaTemplate/cxx17-inline-variables.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -std=c++17 -verify %s -// expected-no-diagnostics + template struct DominatorTreeBase { static constexpr bool IsPostDominator = true; }; @@ -27,3 +27,45 @@ template constexpr int A::n = sizeof(A) + sizeof(T); template inline constexpr int A::m = sizeof(A) + sizeof(T); static_assert(A().f() == 5); static_assert(A().g() == 5); + +namespace GH135032 { + +template struct InlineAuto { + template inline static auto var = 5; +}; + +template struct PartialInlineAuto { + template inline static auto var = 6; + template inline static auto var = 7; +}; + +int inline_auto = InlineAuto::var; +int partial_inline_auto = PartialInlineAuto::var; + +} + +namespace GH140773 { +template class ConstString { // #ConstString + ConstString(typename T::type) {} // #ConstString-Ctor +}; + +template +struct Foo { + template + static constexpr ConstString kFilename{[] { // #kFileName + return 42; + }}; +}; + +// We don't want to instantiate the member template until it's used! +Foo<> foo; + +auto X = Foo<>::kFilename<'a'>; +// expected-error@#kFileName {{no viable constructor}} +// expected-note@-2 {{in instantiation of static data member}} +// expected-note@#ConstString-Ctor {{candidate template ignored}} +// expected-note@#ConstString-Ctor {{implicit deduction guide}} +// expected-note@#ConstString {{candidate template ignored}} +// expected-note@#ConstString {{implicit deduction guide}} + +}