Skip to content

Commit bf6d24a

Browse files
authored
[Clang] Do not defer variable template instantiation for undeduced types (#141009)
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. Fixes #140773 Fixes #135032 Fixes #134526 Reapplies #138122
1 parent e8ecd2c commit bf6d24a

File tree

4 files changed

+60
-2
lines changed

4 files changed

+60
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,7 @@ Bug Fixes to C++ Support
743743
in a ``constexpr`` function. (#GH131432)
744744
- Fixed an incorrect TreeTransform for calls to ``consteval`` functions if a conversion template is present. (#GH137885)
745745
- Clang now emits a warning when class template argument deduction for alias templates is used in C++17. (#GH133806)
746+
- Fixed a missed initializer instantiation bug for variable templates. (#GH134526), (#GH138122)
746747
- Fix a crash when checking the template template parameters of a dependent lambda appearing in an alias declaration.
747748
(#GH136432), (#GH137014), (#GH138018)
748749
- Fixed an assertion when trying to constant-fold various builtins when the argument

clang/lib/Sema/SemaExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20158,9 +20158,10 @@ static void DoMarkVarDeclReferenced(
2015820158
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
2015920159
}
2016020160

20161-
if (UsableInConstantExpr) {
20161+
if (UsableInConstantExpr || Var->getType()->isUndeducedType()) {
2016220162
// Do not defer instantiations of variables that could be used in a
2016320163
// constant expression.
20164+
// The type deduction also needs a complete initializer.
2016420165
SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] {
2016520166
SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
2016620167
});

clang/test/CodeGenCXX/cxx1z-inline-variables.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s
22

3+
template <typename T> struct InlineAuto {
4+
template <typename G> inline static auto var = 5;
5+
};
6+
int inlineauto = InlineAuto<int>::var<int>;
7+
// CHECK: @_ZN10InlineAutoIiE3varIiEE = {{.*}}i32 5{{.*}}comdat
8+
9+
template <typename> struct PartialInlineAuto {
10+
template <typename, typename> inline static auto var = 6;
11+
template <typename T> inline static auto var<int, T> = 7;
12+
};
13+
14+
int partialinlineauto = PartialInlineAuto<int>::var<int, int>;
15+
// CHECK: @_ZN17PartialInlineAutoIiE3varIiiEE = {{.*}}i32 7{{.*}}comdat
16+
317
struct Q {
418
// CHECK: @_ZN1Q1kE = linkonce_odr constant i32 5, comdat
519
static constexpr int k = 5;

clang/test/SemaTemplate/cxx17-inline-variables.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -std=c++17 -verify %s
2-
// expected-no-diagnostics
2+
33
template<bool> struct DominatorTreeBase {
44
static constexpr bool IsPostDominator = true;
55
};
@@ -27,3 +27,45 @@ template <typename T> constexpr int A<T>::n = sizeof(A) + sizeof(T);
2727
template <typename T> inline constexpr int A<T>::m = sizeof(A) + sizeof(T);
2828
static_assert(A<int>().f() == 5);
2929
static_assert(A<int>().g() == 5);
30+
31+
namespace GH135032 {
32+
33+
template <typename T> struct InlineAuto {
34+
template <typename G> inline static auto var = 5;
35+
};
36+
37+
template <typename> struct PartialInlineAuto {
38+
template <typename, typename> inline static auto var = 6;
39+
template <typename T> inline static auto var<int, T> = 7;
40+
};
41+
42+
int inline_auto = InlineAuto<int>::var<int>;
43+
int partial_inline_auto = PartialInlineAuto<int>::var<int, int>;
44+
45+
}
46+
47+
namespace GH140773 {
48+
template <class T> class ConstString { // #ConstString
49+
ConstString(typename T::type) {} // #ConstString-Ctor
50+
};
51+
52+
template <class = int>
53+
struct Foo {
54+
template <char>
55+
static constexpr ConstString kFilename{[] { // #kFileName
56+
return 42;
57+
}};
58+
};
59+
60+
// We don't want to instantiate the member template until it's used!
61+
Foo<> foo;
62+
63+
auto X = Foo<>::kFilename<'a'>;
64+
// expected-error@#kFileName {{no viable constructor}}
65+
// expected-note@-2 {{in instantiation of static data member}}
66+
// expected-note@#ConstString-Ctor {{candidate template ignored}}
67+
// expected-note@#ConstString-Ctor {{implicit deduction guide}}
68+
// expected-note@#ConstString {{candidate template ignored}}
69+
// expected-note@#ConstString {{implicit deduction guide}}
70+
71+
}

0 commit comments

Comments
 (0)