We may fail to map a declaration in a template to its instantiated
declaration because of interesting ordering dependencies while
instantiating a class template or member class thereof. Complain,
rather than asserting (+Asserts) or silently rejecting the code
(-Asserts).

Fixes the crash-on-invalid in PR8965. 


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127129 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index df43a7e..d7a1c38 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2439,6 +2439,11 @@
 def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
 def err_no_member : Error<"no member named %0 in %1">;
 
+def err_member_not_yet_instantiated : Error<
+  "no member %0 in %1; it has not yet been instantiated">;
+def note_non_instantiated_member_here : Note<
+  "not-yet-instantiated member is declared here">;
+
 def err_member_redeclared : Error<"class member cannot be redeclared">;
 def err_member_name_of_class : Error<"member %0 has the same name as its class">;
 def err_member_def_undefined_record : Error<
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 0b46642..102ef51 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3001,11 +3001,14 @@
 
     // If our context used to be dependent, we may need to instantiate
     // it before performing lookup into that context.
+    bool IsBeingInstantiated = false;
     if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) {
       if (!Spec->isDependentContext()) {
         QualType T = Context.getTypeDeclType(Spec);
         const RecordType *Tag = T->getAs<RecordType>();
         assert(Tag && "type of non-dependent record is not a RecordType");
+        if (Tag->isBeingDefined())
+          IsBeingInstantiated = true;
         if (!Tag->isBeingDefined() &&
             RequireCompleteType(Loc, T, diag::err_incomplete_type))
           return 0;
@@ -3032,13 +3035,29 @@
                                    ParentDC->decls_end());
     }
 
-    // UsingShadowDecls can instantiate to nothing because of using hiding.
-    // Note: this assertion end up firing in invalid code even when none of the 
-    // AST invariants have been broken, so we explicitly check whether any
-    // errors have been emitted
-    assert((Result || isa<UsingShadowDecl>(D) || Diags.hasErrorOccurred()) &&
-           "Unable to find instantiation of declaration!");
-
+    if (!Result) {
+      if (isa<UsingShadowDecl>(D)) {
+        // UsingShadowDecls can instantiate to nothing because of using hiding.
+      } else if (Diags.hasErrorOccurred()) {
+        // We've already complained about something, so most likely this
+        // declaration failed to instantiate. There's no point in complaining
+        // further, since this is normal in invalid code.
+      } else if (IsBeingInstantiated) {
+        // The class in which this member exists is currently being 
+        // instantiated, and we haven't gotten around to instantiating this
+        // member yet. This can happen when the code uses forward declarations
+        // of member classes, and introduces ordering dependencies via
+        // template instantiation.
+        Diag(Loc, diag::err_member_not_yet_instantiated)
+          << D->getDeclName()
+          << Context.getTypeDeclType(cast<CXXRecordDecl>(ParentDC));
+        Diag(D->getLocation(), diag::note_non_instantiated_member_here);
+      } else {
+        // We should have found something, but didn't.
+        llvm_unreachable("Unable to find instantiation of declaration!");
+      }
+    }
+    
     D = Result;
   }
 
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
index f1bdf3e..74c2609 100644
--- a/test/SemaTemplate/instantiate-member-class.cpp
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -1,5 +1,28 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
+namespace PR8965 {
+  template<typename T>
+  struct X {
+    typedef int type;
+
+    T field; // expected-note{{in instantiation of member class}}
+  };
+
+  template<typename T>
+  struct Y {
+    struct Inner;
+
+    typedef typename X<Inner>::type // expected-note{{in instantiation of template class}}
+      type; // expected-note{{not-yet-instantiated member is declared here}}
+
+    struct Inner {
+      typedef type field; // expected-error{{no member 'type' in 'PR8965::Y<int>'; it has not yet been instantiated}}
+    };
+  };
+
+  Y<int> y; // expected-note{{in instantiation of template class}}
+}
+
 template<typename T>
 class X {
 public: