-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Clang] Do not defer variable template instantiation for undeduced types #141009
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Younan Zhang (zyn0217) ChangesThe previous approach broke the instantiation convention for templated We deferred variable template instantiation until the end of the TU. Fixes #140773 Full diff: https://github.com/llvm/llvm-project/pull/141009.diff 5 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f04cb7b91788c..026b585826200 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -728,7 +728,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)
-- Fix missed initializer instantiation bug for variable templates. (#GH138122)
+- 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 b18e83b605e4f..37566450cd88c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -20155,9 +20155,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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index b12085c6f6935..d4f99c1fa16f6 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -6032,11 +6032,11 @@ void Sema::BuildVariableInstantiation(
Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
// Figure out whether to eagerly instantiate the initializer.
- if (NewVar->getType()->isUndeducedType()) {
+ if (InstantiatingVarTemplate || 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.
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
- } else if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
- // We're producing a template. Don't instantiate the initializer yet.
} else if (InstantiatingSpecFromTemplate ||
(OldVar->isInline() && OldVar->isThisDeclarationADefinition() &&
!NewVar->isThisDeclarationADefinition())) {
diff --git a/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp b/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp
index 1cb30b178e06f..9b1a6e4647e85 100644
--- a/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp
+++ b/clang/test/CodeGenCXX/cxx1z-inline-variables.cpp
@@ -5,7 +5,7 @@ template <typename T> struct InlineAuto {
};
int inlineauto = InlineAuto<int>::var<int>;
// CHECK: @_ZN10InlineAutoIiE3varIiEE = {{.*}}i32 5{{.*}}comdat
-//
+
template <typename> struct PartialInlineAuto {
template <typename, typename> inline static auto var = 6;
template <typename T> inline static auto var<int, T> = 7;
diff --git a/clang/test/SemaTemplate/cxx17-inline-variables.cpp b/clang/test/SemaTemplate/cxx17-inline-variables.cpp
index 06f1ec17fb7a8..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<bool> struct DominatorTreeBase {
static constexpr bool IsPostDominator = true;
};
@@ -28,6 +28,8 @@ 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);
+namespace GH135032 {
+
template <typename T> struct InlineAuto {
template <typename G> inline static auto var = 5;
};
@@ -37,5 +39,33 @@ template <typename> struct PartialInlineAuto {
template <typename T> inline static auto var<int, T> = 7;
};
-int inlineauto = InlineAuto<int>::var<int>;
-int partialinlineauto = PartialInlineAuto<int>::var<int, int>;
+int inline_auto = InlineAuto<int>::var<int>;
+int partial_inline_auto = PartialInlineAuto<int>::var<int, int>;
+
+}
+
+namespace GH140773 {
+template <class T> class ConstString { // #ConstString
+ ConstString(typename T::type) {} // #ConstString-Ctor
+};
+
+template <class = int>
+struct Foo {
+ template <char>
+ 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}}
+
+}
|
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.
…pes (llvm#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 llvm#140773 Fixes llvm#135032 Fixes llvm#134526 Reapplies llvm#138122
…pes (llvm#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 llvm#140773 Fixes llvm#135032 Fixes llvm#134526 Reapplies llvm#138122
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