During the instantiation of a class template specialization, that
specialization is known to be incomplete. If we're asked to try to
complete it, don't attempt to instantiate it again -- that can lead
to stack overflow, and to rejects-valids if the class being incomplete
is not an error.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153236 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index d8ac763..e83e9ef 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -4181,12 +4181,12 @@
                                                       /*Complain=*/diag != 0);
     } else if (CXXRecordDecl *Rec
                  = dyn_cast<CXXRecordDecl>(Record->getDecl())) {
-      if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
-        MemberSpecializationInfo *MSInfo = Rec->getMemberSpecializationInfo();
-        assert(MSInfo && "Missing member specialization information?");
+      CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass();
+      if (!Rec->isBeingDefined() && Pattern) {
+        MemberSpecializationInfo *MSI = Rec->getMemberSpecializationInfo();
+        assert(MSI && "Missing member specialization information?");
         // This record was instantiated from a class within a template.
-        if (MSInfo->getTemplateSpecializationKind() 
-                                               != TSK_ExplicitSpecialization)
+        if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
           return InstantiateClass(Loc, Rec, Pattern,
                                   getTemplateInstantiationArgs(Rec),
                                   TSK_ImplicitInstantiation,
diff --git a/test/SemaTemplate/instantiate-self.cpp b/test/SemaTemplate/instantiate-self.cpp
new file mode 100644
index 0000000..cfe9025
--- /dev/null
+++ b/test/SemaTemplate/instantiate-self.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// Check that we deal with cases where the instantiation of a class template
+// recursively requires the instantiation of the same template.
+namespace test1 {
+  template<typename T> struct A {
+    struct B { // expected-note {{not complete until the closing '}'}}
+      B b; // expected-error {{has incomplete type 'test1::A<int>::B'}}
+    };
+    B b; // expected-note {{in instantiation of}}
+  };
+  A<int> a; // expected-note {{in instantiation of}}
+}
+
+namespace test2 {
+  template<typename T> struct A {
+    struct B {
+      struct C {};
+      char c[1 + C()]; // expected-error {{invalid operands to binary expression}}
+      friend constexpr int operator+(int, C) { return 4; }
+    };
+    B b; // expected-note {{in instantiation of}}
+  };
+  A<int> a; // expected-note {{in instantiation of}}
+}
+
+namespace test3 {
+  // PR12317
+  template<typename T> struct A {
+    struct B {
+      enum { Val = 1 };
+      char c[1 + Val]; // ok
+    };
+    B b;
+  };
+  A<int> a;
+}
+
+namespace test4 {
+  template<typename T> struct M { typedef int type; };
+  template<typename T> struct A {
+    struct B { // expected-note {{not complete until the closing '}'}}
+      int k[typename A<typename M<T>::type>::B().k[0] + 1]; // expected-error {{incomplete type}}
+    };
+    B b; // expected-note {{in instantiation of}}
+  };
+  A<int> a; // expected-note {{in instantiation of}}
+}
+
+// FIXME: PR12298: Recursive constexpr function template instantiation leads to
+// stack overflow.
+#if 0
+namespace test5 {
+  template<typename T> struct A {
+    constexpr T f(T k) { return g(k); }
+    constexpr T g(T k) {
+      return k ? f(k-1)+1 : 0;
+    }
+  };
+  // This should be accepted.
+  constexpr int x = A<int>().f(5);
+}
+
+namespace test6 {
+  template<typename T> constexpr T f(T);
+  template<typename T> constexpr T g(T t) {
+    typedef int arr[f(T())];
+    return t;
+  }
+  template<typename T> constexpr T f(T t) {
+    typedef int arr[g(T())];
+    return t;
+  }
+  // This should be ill-formed.
+  int n = f(0);
+}
+
+namespace test7 {
+  template<typename T> constexpr T g(T t) {
+    return t;
+  }
+  template<typename T> constexpr T f(T t) {
+    typedef int arr[g(T())];
+    return t;
+  }
+  // This should be accepted.
+  int n = f(0);
+}
+#endif