erik.pilkington created this revision.
erik.pilkington added reviewers: rsmith, rjmccall.
Herald added subscribers: dexonsmith, jkorous.
Herald added a project: clang.

This patch fixes a regression introduced in r359947. Here:

  template <class T2> struct Outer {
    template <class T1> static constexpr auto x = 1;
  };
  
  int main() {
    Outer<int> x;
    int i = x.x<int>;
  }

We'd defer the instantiation of the initializer of the variable template when 
instantiating Outer<int> (leaving the variable template with an undeduced 
type). We do eventually instantiate the initializer and deduce the type of the 
variable when we're marking `Outer<int>::x<int>` referenced, but not before 
forming a MemberExpr that refers to the undeduced type. I think we could avoid 
instantiating the initializer of the variable template here, but that doesn't 
appear to be the intent of r359947, so this patch just falls back to the 8.0 
behaviour.

Fixes rdar://52619644

Thanks for taking a look!
Erik


Repository:
  rC Clang

https://reviews.llvm.org/D65022

Files:
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp


Index: clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -395,3 +395,20 @@
   }
   int &t = B::template n; // expected-error {{use of variable template 'n' 
requires template arguments}}
 }
+
+#ifndef PRECXX11
+namespace auto_variable_instantiate_initializer {
+template <class T2> struct S {
+  template <class T> static constexpr auto v = 1;
+  template <class T> static constexpr auto v2 = T{};
+};
+
+void useit() {
+  S<int> x;
+  // We used to fail to instantiate the initializer, leading to an auto type
+  // leaking through here.
+  int i = x.v<float>;
+  float j = x.v2<float>;
+}
+}
+#endif
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4506,11 +4506,11 @@
   Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
 
   // Figure out whether to eagerly instantiate the initializer.
-  if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
-    // We're producing a template. Don't instantiate the initializer yet.
-  } else if (NewVar->getType()->isUndeducedType()) {
+  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())) {


Index: clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -395,3 +395,20 @@
   }
   int &t = B::template n; // expected-error {{use of variable template 'n' requires template arguments}}
 }
+
+#ifndef PRECXX11
+namespace auto_variable_instantiate_initializer {
+template <class T2> struct S {
+  template <class T> static constexpr auto v = 1;
+  template <class T> static constexpr auto v2 = T{};
+};
+
+void useit() {
+  S<int> x;
+  // We used to fail to instantiate the initializer, leading to an auto type
+  // leaking through here.
+  int i = x.v<float>;
+  float j = x.v2<float>;
+}
+}
+#endif
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4506,11 +4506,11 @@
   Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
 
   // Figure out whether to eagerly instantiate the initializer.
-  if (InstantiatingVarTemplate || InstantiatingVarTemplatePartialSpec) {
-    // We're producing a template. Don't instantiate the initializer yet.
-  } else if (NewVar->getType()->isUndeducedType()) {
+  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())) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D65022: [... Erik Pilkington via Phabricator via cfe-commits

Reply via email to