Ensure that type definitions present in just-loaded modules are
visible.

The basic problem here is that a given translation unit can use
forward declarations to form pointers to a given type, say,

  class X;
  X *x;

and then import a module that includes a definition of X:

  import XDef;

We will then fail when attempting to access a member of X, e.g., 

  x->method()

because the AST reader did not know to look for a default of a class
named X within the new module.

This implementation is a bit of a C-centric hack, because the only
definitions that can have this property are enums, structs, unions,
Objective-C classes, and Objective-C protocols, and all of those are
either visible at the top-level or can't be defined later. Hence, we
can use the out-of-date-ness of the name and the identifier-update
mechanism to force the update.

In C++, we will not be so lucky, and will need a more advanced
solution, because the definitions could be in namespaces defined in
two different modules, e.g.,

  // module 1
  namespace N { struct X; }

  // module 2
  namespace N { struct X { /* ... */ }; }

One possible implementation here is for C++ to extend the information
associated with each identifier table to include the declaration IDs
of any definitions associated with that name, regardless of
context. We would have to eagerly load those definitions.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174794 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index cdf921d..85ed3ba 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2612,6 +2612,16 @@
 TagDecl *TagDecl::getDefinition() const {
   if (isCompleteDefinition())
     return const_cast<TagDecl *>(this);
+
+  // If it's possible for us to have an out-of-date definition, check now.
+  if (MayHaveOutOfDateDef) {
+    if (IdentifierInfo *II = getIdentifier()) {
+      if (II->isOutOfDate()) {
+        updateOutOfDate(*II);
+      }
+    }
+  }
+
   if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this))
     return CXXRD->getDefinition();
 
@@ -2668,14 +2678,17 @@
                            bool IsScopedUsingClassTag, bool IsFixed) {
   EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl,
                                     IsScoped, IsScopedUsingClassTag, IsFixed);
+  Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
   C.getTypeDeclType(Enum, PrevDecl);
   return Enum;
 }
 
 EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumDecl));
-  return new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
-                            false, false, false);
+  EnumDecl *Enum = new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(),
+                                      0, 0, false, false, false);
+  Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+  return Enum;
 }
 
 void EnumDecl::completeDefinition(QualType NewType,
@@ -2743,14 +2756,18 @@
                                IdentifierInfo *Id, RecordDecl* PrevDecl) {
   RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id,
                                      PrevDecl);
+  R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+
   C.getTypeDeclType(R, PrevDecl);
   return R;
 }
 
 RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl));
-  return new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
-                              SourceLocation(), 0, 0);
+  RecordDecl *R = new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
+                                       SourceLocation(), 0, 0);
+  R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+  return R;
 }
 
 bool RecordDecl::isInjectedClassName() const {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index e1202c2..2073658 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -40,6 +40,10 @@
 #define ABSTRACT_DECL(DECL)
 #include "clang/AST/DeclNodes.inc"
 
+void Decl::updateOutOfDate(IdentifierInfo &II) const {
+  getASTContext().getExternalSource()->updateOutOfDateIdentifier(II);
+}
+
 void *Decl::AllocateDeserializedDecl(const ASTContext &Context, 
                                      unsigned ID,
                                      unsigned Size) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 90a2b4a..4dd3694 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -87,6 +87,7 @@
                                      bool DelayTypeCreation) {
   CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc,
                                            Id, PrevDecl);
+  R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
 
   // FIXME: DelayTypeCreation seems like such a hack
   if (!DelayTypeCreation)
@@ -101,6 +102,7 @@
                                            0, 0);
   R->IsBeingDefined = true;
   R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
+  R->MayHaveOutOfDateDef = false;
   C.getTypeDeclType(R, /*PrevDecl=*/0);
   return R;
 }
@@ -108,8 +110,11 @@
 CXXRecordDecl *
 CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl));
-  return new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
-                                 SourceLocation(), 0, 0);
+  CXXRecordDecl *R = new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0,
+                                             SourceLocation(), SourceLocation(),
+                                             0, 0);
+  R->MayHaveOutOfDateDef = false;
+  return R;
 }
 
 void
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index b99c45c..ce765a7 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -301,8 +301,8 @@
 
 void ObjCInterfaceDecl::allocateDefinitionData() {
   assert(!hasDefinition() && "ObjC class already has a definition");
-  Data = new (getASTContext()) DefinitionData();
-  Data->Definition = this;
+  Data.setPointer(new (getASTContext()) DefinitionData());
+  Data.getPointer()->Definition = this;
 
   // Make the type point at the definition, now that we have one.
   if (TypeForDecl)
@@ -1011,6 +1011,7 @@
                                              bool isInternal){
   ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, 
                                                         PrevDecl, isInternal);
+  Result->Data.setInt(!C.getLangOpts().Modules);
   C.getObjCInterfaceType(Result, PrevDecl);
   return Result;
 }
@@ -1018,8 +1019,11 @@
 ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C, 
                                                          unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl));
-  return new (Mem) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
-                                     0, false);
+  ObjCInterfaceDecl *Result = new (Mem) ObjCInterfaceDecl(0, SourceLocation(),
+                                                          0, SourceLocation(),
+                                                          0, false);
+  Result->Data.setInt(!C.getLangOpts().Modules);
+  return Result;
 }
 
 ObjCInterfaceDecl::
@@ -1334,15 +1338,17 @@
                                            ObjCProtocolDecl *PrevDecl) {
   ObjCProtocolDecl *Result 
     = new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl);
-  
+  Result->Data.setInt(!C.getLangOpts().Modules);
   return Result;
 }
 
 ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C, 
                                                        unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl));
-  return new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), SourceLocation(),
-                                    0);
+  ObjCProtocolDecl *Result = new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(),
+                                                        SourceLocation(), 0);
+  Result->Data.setInt(!C.getLangOpts().Modules);
+  return Result;
 }
 
 ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
@@ -1380,9 +1386,9 @@
 }
 
 void ObjCProtocolDecl::allocateDefinitionData() {
-  assert(!Data && "Protocol already has a definition!");
-  Data = new (getASTContext()) DefinitionData;
-  Data->Definition = this;
+  assert(!Data.getPointer() && "Protocol already has a definition!");
+  Data.setPointer(new (getASTContext()) DefinitionData);
+  Data.getPointer()->Definition = this;
 }
 
 void ObjCProtocolDecl::startDefinition() {
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index bd5ab8a..42929aa 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -728,6 +728,8 @@
                                                    SpecializedTemplate,
                                                    Args, NumArgs,
                                                    PrevDecl);
+  Result->MayHaveOutOfDateDef = false;
+
   Context.getTypeDeclType(Result, PrevDecl);
   return Result;
 }
@@ -737,7 +739,10 @@
                                                     unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, 
                                        sizeof(ClassTemplateSpecializationDecl));
-  return new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+  ClassTemplateSpecializationDecl *Result =
+    new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+  Result->MayHaveOutOfDateDef = false;
+  return Result;
 }
 
 void
@@ -857,6 +862,7 @@
                                                           PrevDecl,
                                                           SequenceNumber);
   Result->setSpecializationKind(TSK_ExplicitSpecialization);
+  Result->MayHaveOutOfDateDef = false;
 
   Context.getInjectedClassNameType(Result, CanonInjectedType);
   return Result;
@@ -867,7 +873,10 @@
                                                            unsigned ID) {
   void *Mem = AllocateDeserializedDecl(C, ID, 
                 sizeof(ClassTemplatePartialSpecializationDecl));
-  return new (Mem) ClassTemplatePartialSpecializationDecl();
+  ClassTemplatePartialSpecializationDecl *Result
+    = new (Mem) ClassTemplatePartialSpecializationDecl();
+  Result->MayHaveOutOfDateDef = false;
+  return Result;
 }
 
 //===----------------------------------------------------------------------===//