diff options
| -rw-r--r-- | clang/include/clang/Basic/IdentifierTable.h | 46 | ||||
| -rw-r--r-- | clang/include/clang/Lex/ExternalPreprocessorSource.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/Sema/IdentifierResolver.h | 32 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 8 | ||||
| -rw-r--r-- | clang/include/clang/Serialization/ASTReader.h | 3 | ||||
| -rw-r--r-- | clang/include/clang/Serialization/ASTWriter.h | 4 | ||||
| -rw-r--r-- | clang/lib/Basic/IdentifierTable.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Lex/Pragma.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Sema/IdentifierResolver.cpp | 165 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.cpp | 12 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 135 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 52 | ||||
| -rw-r--r-- | clang/test/Modules/redeclarations.m | 22 | 
16 files changed, 362 insertions, 140 deletions
diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 5e48a866197..d7d0ded0200 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -49,8 +49,6 @@ namespace clang {  /// variable or function name).  The preprocessor keeps this information in a  /// set, and all tok::identifier tokens have a pointer to one of these.  class IdentifierInfo { -  // Note: DON'T make TokenID a 'tok::TokenKind'; MSVC will treat it as a -  //       signed char and TokenKinds > 255 won't be handled correctly.    unsigned TokenID            : 9; // Front-end token ID or tok::identifier.    // Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf).    // First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values @@ -62,11 +60,17 @@ class IdentifierInfo {    bool IsPoisoned             : 1; // True if identifier is poisoned.    bool IsCPPOperatorKeyword   : 1; // True if ident is a C++ operator keyword.    bool NeedsHandleIdentifier  : 1; // See "RecomputeNeedsHandleIdentifier". -  bool IsFromAST              : 1; // True if identfier first appeared in an AST -                                   // file and wasn't modified since. +  bool IsFromAST              : 1; // True if identifier was loaded (at least  +                                   // partially) from an AST file. +  bool ChangedAfterLoad       : 1; // True if identifier has changed from the +                                   // definition loaded from an AST file.    bool RevertedTokenID        : 1; // True if RevertTokenIDToIdentifier was                                     // called. -  // 5 bits left in 32-bit word. +  bool OutOfDate              : 1; // True if there may be additional +                                   // information about this identifier +                                   // stored externally. +  // 2 bits left in 32-bit word. +      void *FETokenInfo;               // Managed by the language front-end.    llvm::StringMapEntry<IdentifierInfo*> *Entry; @@ -132,7 +136,6 @@ public:        NeedsHandleIdentifier = 1;      else        RecomputeNeedsHandleIdentifier(); -    IsFromAST = false;    }    /// getTokenID - If this is a source-language token (e.g. 'for'), this API @@ -221,7 +224,6 @@ public:        NeedsHandleIdentifier = 1;      else        RecomputeNeedsHandleIdentifier(); -    IsFromAST = false;    }    /// isPoisoned - Return true if this token has been poisoned. @@ -253,8 +255,34 @@ public:    /// from an AST file.    bool isFromAST() const { return IsFromAST; } -  void setIsFromAST(bool FromAST = true) { IsFromAST = FromAST; } +  void setIsFromAST() { IsFromAST = true; } + +  /// \brief Determine whether this identifier has changed since it was loaded +  /// from an AST file. +  bool hasChangedSinceDeserialization() const { +    return ChangedAfterLoad; +  } +   +  /// \brief Note that this identifier has changed since it was loaded from +  /// an AST file. +  void setChangedSinceDeserialization() { +    ChangedAfterLoad = true; +  } +  /// \brief Determine whether the information for this identifier is out of +  /// date with respect to the external source. +  bool isOutOfDate() const { return OutOfDate; } +   +  /// \brief Set whether the information for this identifier is out of +  /// date with respect to the external source. +  void setOutOfDate(bool OOD) { +    OutOfDate = OOD; +    if (OOD) +      NeedsHandleIdentifier = true; +    else +      RecomputeNeedsHandleIdentifier(); +  } +    private:    /// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does    /// several special (but rare) things to identifiers of various sorts.  For @@ -266,7 +294,7 @@ private:    void RecomputeNeedsHandleIdentifier() {      NeedsHandleIdentifier =        (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() | -       isExtensionToken() | isCXX11CompatKeyword() || +       isExtensionToken() | isCXX11CompatKeyword() || isOutOfDate() ||         (getTokenID() == tok::kw___import_module__));    }  }; diff --git a/clang/include/clang/Lex/ExternalPreprocessorSource.h b/clang/include/clang/Lex/ExternalPreprocessorSource.h index dbf73890337..f172b5c8d22 100644 --- a/clang/include/clang/Lex/ExternalPreprocessorSource.h +++ b/clang/include/clang/Lex/ExternalPreprocessorSource.h @@ -30,6 +30,9 @@ public:    /// \brief Read the definition for the given macro.    virtual void LoadMacroDefinition(IdentifierInfo *II) = 0; +   +  /// \brief Update an out-of-date identifier. +  virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0;  };  } diff --git a/clang/include/clang/Sema/IdentifierResolver.h b/clang/include/clang/Sema/IdentifierResolver.h index 85d8ad22bfb..cea913c4941 100644 --- a/clang/include/clang/Sema/IdentifierResolver.h +++ b/clang/include/clang/Sema/IdentifierResolver.h @@ -23,9 +23,11 @@ class ASTContext;  class Decl;  class DeclContext;  class DeclarationName; +class ExternalPreprocessorSource;  class NamedDecl; +class Preprocessor;  class Scope; - +    /// IdentifierResolver - Keeps track of shadowed decls on enclosing  /// scopes.  It manages the shadowing chains of declaration names and  /// implements efficient decl lookup based on a declaration name. @@ -141,10 +143,10 @@ public:    };    /// begin - Returns an iterator for decls with the name 'Name'. -  static iterator begin(DeclarationName Name); +  iterator begin(DeclarationName Name);    /// end - Returns an iterator that has 'finished'. -  static iterator end() { +  iterator end() {      return iterator();    } @@ -175,23 +177,29 @@ public:    /// position.    void InsertDeclAfter(iterator Pos, NamedDecl *D); -  /// \brief Link the declaration into the chain of declarations for -  /// the given identifier. +  /// \brief Try to add the given declaration to the top level scope, if it +  /// (or a redeclaration of it) hasn't already been added.    /// -  /// This is a lower-level routine used by the AST reader to link a -  /// declaration into a specific IdentifierInfo before the -  /// declaration actually has a name. -  void AddDeclToIdentifierChain(IdentifierInfo *II, NamedDecl *D); - -  explicit IdentifierResolver(const LangOptions &LangOpt); +  /// \param D The externally-produced declaration to add. +  /// +  /// \param Name The name of the externally-produced declaration. +  /// +  /// \returns true if the declaration was added, false otherwise. +  bool tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name); +   +  explicit IdentifierResolver(Preprocessor &PP);    ~IdentifierResolver();  private:    const LangOptions &LangOpt; - +  Preprocessor &PP; +      class IdDeclInfoMap;    IdDeclInfoMap *IdDeclInfos; +  void updatingIdentifier(IdentifierInfo &II); +  void readingIdentifier(IdentifierInfo &II); +      /// FETokenInfo contains a Decl pointer if lower bit == 0.    static inline bool isDeclPtr(void *Ptr) {      return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a0f4a628fa1..cba8134fca4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1302,6 +1302,14 @@ public:    /// Add this decl to the scope shadowed decl chains.    void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); +  /// \brief Make the given externally-produced declaration visible at the +  /// top level scope. +  /// +  /// \param D The externally-produced declaration to push. +  /// +  /// \param Name The name of the externally-produced declaration. +  void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); +      /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true    /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns    /// true if 'D' belongs to the given declaration context. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index b1a514df49a..6470fd634e3 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1256,6 +1256,9 @@ public:    /// \brief Read the macro definition for this identifier.    virtual void LoadMacroDefinition(IdentifierInfo *II); +  /// \brief Update an out-of-date identifier. +  virtual void updateOutOfDateIdentifier(IdentifierInfo &II); +    /// \brief Read the macro definition corresponding to this iterator    /// into the unread macro record offsets table.    void LoadMacroDefinition( diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 7d89ce7db05..44d88258297 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -44,6 +44,7 @@ class CXXBaseSpecifier;  class CXXCtorInitializer;  class FPOptions;  class HeaderSearch; +class IdentifierResolver;  class MacroDefinition;  class MemorizeStatCalls;  class OpaqueValueExpr; @@ -355,7 +356,8 @@ private:    void WriteTypeDeclOffsets();    void WriteSelectors(Sema &SemaRef);    void WriteReferencedSelectorsPool(Sema &SemaRef); -  void WriteIdentifierTable(Preprocessor &PP, bool IsModule); +  void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, +                            bool IsModule);    void WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record);    void ResolveDeclUpdatesBlocks();    void WriteDeclUpdatesBlocks(); diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 78f8a7cbdbf..94ca1789f39 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -37,7 +37,9 @@ IdentifierInfo::IdentifierInfo() {    IsCPPOperatorKeyword = false;    NeedsHandleIdentifier = false;    IsFromAST = false; +  ChangedAfterLoad = false;    RevertedTokenID = false; +  OutOfDate = false;    FETokenInfo = 0;    Entry = 0;  } diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 50929158b24..7557f2e0fe0 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -51,9 +51,13 @@ void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {    if (MI) {      Macros[II] = MI;      II->setHasMacroDefinition(true); +    if (II->isFromAST()) +      II->setChangedSinceDeserialization();    } else if (II->hasMacroDefinition()) {      Macros.erase(II);      II->setHasMacroDefinition(false); +    if (II->isFromAST()) +      II->setChangedSinceDeserialization();    }  } diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index f6532c2175a..cc612fff9ff 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -304,6 +304,8 @@ void Preprocessor::HandlePragmaPoison(Token &PoisonTok) {      // Finally, poison it!      II->setIsPoisoned(); +    if (II->isFromAST()) +      II->setChangedSinceDeserialization();    }  } diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 31662ad0c11..af0faca43b9 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -492,6 +492,13 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {    IdentifierInfo &II = *Identifier.getIdentifierInfo(); +  // If the information about this identifier is out of date, update it from +  // the external source. +  if (II.isOutOfDate()) { +    ExternalSource->updateOutOfDateIdentifier(II); +    Identifier.setKind(II.getTokenID()); +  } +      // If this identifier was poisoned, and if it was not produced from a macro    // expansion, emit an error.    if (II.isPoisoned() && CurPPLexer) { diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index a6432670856..812f5d64faa 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -15,7 +15,10 @@  #include "clang/Sema/IdentifierResolver.h"  #include "clang/Sema/Scope.h"  #include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h"  #include "clang/Basic/LangOptions.h" +#include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/Preprocessor.h"  using namespace clang; @@ -93,9 +96,11 @@ IdentifierResolver::IdDeclInfo::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {  // IdentifierResolver Implementation  //===----------------------------------------------------------------------===// -IdentifierResolver::IdentifierResolver(const LangOptions &langOpt) -    : LangOpt(langOpt), IdDeclInfos(new IdDeclInfoMap) { +IdentifierResolver::IdentifierResolver(Preprocessor &PP) +  : LangOpt(PP.getLangOptions()), PP(PP), +    IdDeclInfos(new IdDeclInfoMap) {  } +  IdentifierResolver::~IdentifierResolver() {    delete IdDeclInfos;  } @@ -146,7 +151,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,  void IdentifierResolver::AddDecl(NamedDecl *D) {    DeclarationName Name = D->getDeclName();    if (IdentifierInfo *II = Name.getAsIdentifierInfo()) -    II->setIsFromAST(false); +    updatingIdentifier(*II);    void *Ptr = Name.getFETokenInfo<void>(); @@ -170,6 +175,9 @@ void IdentifierResolver::AddDecl(NamedDecl *D) {  void IdentifierResolver::InsertDeclAfter(iterator Pos, NamedDecl *D) {    DeclarationName Name = D->getDeclName(); +  if (IdentifierInfo *II = Name.getAsIdentifierInfo()) +    updatingIdentifier(*II); +      void *Ptr = Name.getFETokenInfo<void>();    if (!Ptr) { @@ -195,7 +203,8 @@ void IdentifierResolver::InsertDeclAfter(iterator Pos, NamedDecl *D) {    }    if (IdentifierInfo *II = Name.getAsIdentifierInfo()) -    II->setIsFromAST(false); +    if (II->isFromAST()) +      II->setChangedSinceDeserialization();    // General case: insert the declaration at the appropriate point in the     // list, which already has at least two elements. @@ -212,7 +221,7 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) {    assert(D && "null param passed");    DeclarationName Name = D->getDeclName();    if (IdentifierInfo *II = Name.getAsIdentifierInfo()) -    II->setIsFromAST(false); +    updatingIdentifier(*II);    void *Ptr = Name.getFETokenInfo<void>(); @@ -233,7 +242,7 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {    DeclarationName Name = Old->getDeclName();    if (IdentifierInfo *II = Name.getAsIdentifierInfo()) -    II->setIsFromAST(false); +    updatingIdentifier(*II);    void *Ptr = Name.getFETokenInfo<void>(); @@ -254,6 +263,9 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) {  /// begin - Returns an iterator for decls with name 'Name'.  IdentifierResolver::iterator  IdentifierResolver::begin(DeclarationName Name) { +  if (IdentifierInfo *II = Name.getAsIdentifierInfo()) +    readingIdentifier(*II); +        void *Ptr = Name.getFETokenInfo<void>();    if (!Ptr) return end(); @@ -269,27 +281,142 @@ IdentifierResolver::begin(DeclarationName Name) {    return end();  } -void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II, -                                                  NamedDecl *D) { -  II->setIsFromAST(false); -  void *Ptr = II->getFETokenInfo<void>(); +namespace { +  enum DeclMatchKind { +    DMK_Different, +    DMK_Replace, +    DMK_Ignore +  }; +} -  if (!Ptr) { -    II->setFETokenInfo(D); -    return; +/// \brief Compare two declarations to see whether they are different or, +/// if they are the same, whether the new declaration should replace the  +/// existing declaration. +static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) { +  // If the declarations are identical, ignore the new one. +  if (Existing == New) +    return DMK_Ignore; + +  // If the declarations have different kinds, they're obviously different. +  if (Existing->getKind() != New->getKind()) +    return DMK_Different; + +  // If the declarations are redeclarations of each other, keep the newest one. +  if (Existing->getCanonicalDecl() == New->getCanonicalDecl()) { +    // If the existing declaration is somewhere in the previous declaration +    // chain of the new declaration, then prefer the new declaration. +    for (Decl::redecl_iterator RD = New->redecls_begin(),  +                            RDEnd = New->redecls_end(); +         RD != RDEnd; ++RD) { +      if (*RD == Existing) +        return DMK_Replace; +         +      if (RD->isCanonicalDecl()) +        break; +    } +     +    return DMK_Ignore;    } +   +  // If the declarations are both Objective-C classes, and one is a forward +  // declaration and the other is not, take the full definition. +  // FIXME: At some point, we'll actually have to detect collisions better. +  // This logic, however, belongs in the AST reader, not here. +  if (ObjCInterfaceDecl *ExistingIFace = dyn_cast<ObjCInterfaceDecl>(Existing)) +    if (ObjCInterfaceDecl *NewIFace = dyn_cast<ObjCInterfaceDecl>(New)) +      if (ExistingIFace->isForwardDecl() != NewIFace->isForwardDecl()) +        return ExistingIFace->isForwardDecl()? DMK_Replace : DMK_Ignore; +         +  return DMK_Different; +} +bool IdentifierResolver::tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name){ +  if (IdentifierInfo *II = Name.getAsIdentifierInfo()) +    updatingIdentifier(*II); +   +  void *Ptr = Name.getFETokenInfo<void>(); +     +  if (!Ptr) { +    Name.setFETokenInfo(D); +    return true; +  } +      IdDeclInfo *IDI; - +      if (isDeclPtr(Ptr)) { -    II->setFETokenInfo(NULL); -    IDI = &(*IdDeclInfos)[II];      NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); -    IDI->AddDecl(PrevD); -  } else -    IDI = toIdDeclInfo(Ptr); +     +    switch (compareDeclarations(PrevD, D)) { +    case DMK_Different: +      break; +       +    case DMK_Ignore: +      return false; +       +    case DMK_Replace: +      Name.setFETokenInfo(D); +      return true; +    } +     +    Name.setFETokenInfo(NULL); +    IDI = &(*IdDeclInfos)[Name]; +     +    // If the existing declaration is not visible in translation unit scope, +    // then add the new top-level declaration first. +    if (!PrevD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { +      IDI->AddDecl(D); +      IDI->AddDecl(PrevD); +    } else { +      IDI->AddDecl(PrevD); +      IDI->AddDecl(D); +    } +    return true; +  }  +   +  IDI = toIdDeclInfo(Ptr); +  // See whether this declaration is identical to any existing declarations. +  // If not, find the right place to insert it. +  for (IdDeclInfo::DeclsTy::iterator I = IDI->decls_begin(),  +                                  IEnd = IDI->decls_end(); +       I != IEnd; ++I) { +     +    switch (compareDeclarations(*I, D)) { +    case DMK_Different: +      break; +       +    case DMK_Ignore: +      return false; +       +    case DMK_Replace: +      *I = D; +      return true; +    } +     +    if (!(*I)->getDeclContext()->getRedeclContext()->isTranslationUnit()) { +      // We've found a declaration that is not visible from the translation +      // unit (it's in an inner scope). Insert our declaration here. +      IDI->InsertDecl(I, D); +      return true; +    } +  } +   +  // Add the declaration to the end.    IDI->AddDecl(D); +  return true; +} + +void IdentifierResolver::readingIdentifier(IdentifierInfo &II) { +  if (II.isOutOfDate()) +    PP.getExternalSource()->updateOutOfDateIdentifier(II);   +} + +void IdentifierResolver::updatingIdentifier(IdentifierInfo &II) { +  if (II.isOutOfDate()) +    PP.getExternalSource()->updateOutOfDateIdentifier(II); +   +  if (II.isFromAST()) +    II.setChangedSinceDeserialization();  }  //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 8346cc475ff..9b788a7058b 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -98,7 +98,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,      CurContext(0), OriginalLexicalContext(0),      PackContext(0), MSStructPragmaOn(false), VisContext(0),      ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0), -    IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), +    IdResolver(pp), CXXTypeInfoDecl(0), MSVCGuidDecl(0),      GlobalNewDeleteDeclared(false),       ObjCShouldCallSuperDealloc(false),      ObjCShouldCallSuperFinalize(false), @@ -143,11 +143,11 @@ void Sema::Initialize() {      // If either of the 128-bit integer types are unavailable to name lookup,      // define them now.      DeclarationName Int128 = &Context.Idents.get("__int128_t"); -    if (IdentifierResolver::begin(Int128) == IdentifierResolver::end()) +    if (IdResolver.begin(Int128) == IdResolver.end())        PushOnScopeChains(Context.getInt128Decl(), TUScope);      DeclarationName UInt128 = &Context.Idents.get("__uint128_t"); -    if (IdentifierResolver::begin(UInt128) == IdentifierResolver::end()) +    if (IdResolver.begin(UInt128) == IdResolver.end())        PushOnScopeChains(Context.getUInt128Decl(), TUScope);    } @@ -157,18 +157,18 @@ void Sema::Initialize() {      // If 'SEL' does not yet refer to any declarations, make it refer to the      // predefined 'SEL'.      DeclarationName SEL = &Context.Idents.get("SEL"); -    if (IdentifierResolver::begin(SEL) == IdentifierResolver::end()) +    if (IdResolver.begin(SEL) == IdResolver.end())        PushOnScopeChains(Context.getObjCSelDecl(), TUScope);      // If 'id' does not yet refer to any declarations, make it refer to the      // predefined 'id'.      DeclarationName Id = &Context.Idents.get("id"); -    if (IdentifierResolver::begin(Id) == IdentifierResolver::end()) +    if (IdResolver.begin(Id) == IdResolver.end())        PushOnScopeChains(Context.getObjCIdDecl(), TUScope);      // Create the built-in typedef for 'Class'.      DeclarationName Class = &Context.Idents.get("Class"); -    if (IdentifierResolver::begin(Class) == IdentifierResolver::end()) +    if (IdResolver.begin(Class) == IdResolver.end())        PushOnScopeChains(Context.getObjCClassDecl(), TUScope);    }  } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5f26c3185be..fb00c918ab5 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -938,6 +938,11 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {    }  } +void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) { +  if (IdResolver.tryAddTopLevelDecl(D, Name) && TUScope) +    TUScope->AddDecl(D); +} +  bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,                           bool ExplicitInstantiationOrSpecialization) {    return IdResolver.isDeclInScope(D, Ctx, Context, S, diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index d47bb3701dd..5898ff09617 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -514,6 +514,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,        II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));      Reader.SetIdentifierInfo(ID, II);      II->setIsFromAST(); +    II->setOutOfDate(false);      return II;    } @@ -539,7 +540,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,    IdentifierInfo *II = KnownII;    if (!II)      II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second)); -  Reader.SetIdentifierInfo(ID, II); +  II->setOutOfDate(false); +  II->setIsFromAST();    // Set or check the various bits in the IdentifierInfo structure.    // Token IDs are read-only. @@ -564,6 +566,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,      DataLen -= 4;    } +  Reader.SetIdentifierInfo(ID, II); +    // Read all of the declarations visible at global scope with this    // name.    if (DataLen > 0) { @@ -573,7 +577,6 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,      Reader.SetGloballyVisibleDecls(II, DeclIDs);    } -  II->setIsFromAST();    return II;  } @@ -1276,6 +1279,7 @@ void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {          Error("macro must have a name in AST file");          return;        } +              SourceLocation Loc = ReadSourceLocation(F, Record[1]);        bool isUsed = Record[2]; @@ -1500,6 +1504,46 @@ void ASTReader::LoadMacroDefinition(IdentifierInfo *II) {    LoadMacroDefinition(Pos);  } +namespace { +  /// \brief Visitor class used to look up identifirs in an AST file. +  class IdentifierLookupVisitor { +    StringRef Name; +    IdentifierInfo *Found; +  public: +    explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { } +     +    static bool visit(Module &M, void *UserData) { +      IdentifierLookupVisitor *This +        = static_cast<IdentifierLookupVisitor *>(UserData); +       +      ASTIdentifierLookupTable *IdTable +        = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; +      if (!IdTable) +        return false; +       +      std::pair<const char*, unsigned> Key(This->Name.begin(),  +                                           This->Name.size()); +      ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key); +      if (Pos == IdTable->end()) +        return false; +       +      // Dereferencing the iterator has the effect of building the +      // IdentifierInfo node and populating it with the various +      // declarations it needs. +      This->Found = *Pos; +      return true; +    } +     +    // \brief Retrieve the identifier info found within the module +    // files. +    IdentifierInfo *getIdentifierInfo() const { return Found; } +  }; +} + +void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { +  get(II.getName()); +} +  const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) {    std::string Filename = filenameStrRef;    MaybeAddSystemRootToFilename(Filename); @@ -2329,43 +2373,6 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(Module &M) {    return Success;  } -namespace { -  /// \brief Visitor class used to look up identifirs in an AST file. -  class IdentifierLookupVisitor { -    StringRef Name; -    IdentifierInfo *Found; -  public: -    explicit IdentifierLookupVisitor(StringRef Name) : Name(Name), Found() { } -     -    static bool visit(Module &M, void *UserData) { -      IdentifierLookupVisitor *This -      = static_cast<IdentifierLookupVisitor *>(UserData); -       -      ASTIdentifierLookupTable *IdTable -        = (ASTIdentifierLookupTable *)M.IdentifierLookupTable; -      if (!IdTable) -        return false; -       -      std::pair<const char*, unsigned> Key(This->Name.begin(),  -                                           This->Name.size()); -      ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key); -      if (Pos == IdTable->end()) -        return false; -       -      // Dereferencing the iterator has the effect of building the -      // IdentifierInfo node and populating it with the various -      // declarations it needs. -      This->Found = *Pos; -      return true; -    } -     -    // \brief Retrieve the identifier info found within the module -    // files. -    IdentifierInfo *getIdentifierInfo() const { return Found; } -  }; -} - -  ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,                                              ModuleKind Type) {    switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) { @@ -2384,33 +2391,13 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,        CheckPredefinesBuffers())      return IgnorePCH; -  // Initialization of keywords and pragmas occurs before the -  // AST file is read, so there may be some identifiers that were -  // loaded into the IdentifierTable before we intercepted the -  // creation of identifiers. Iterate through the list of known -  // identifiers and determine whether we have to establish -  // preprocessor definitions or top-level identifier declaration -  // chains for those identifiers. -  // -  // We copy the IdentifierInfo pointers to a small vector first, -  // since de-serializing declarations or macro definitions can add -  // new entries into the identifier table, invalidating the -  // iterators. -  // -  // FIXME: We need a lazier way to load this information, e.g., by marking -  // the identifier data as 'dirty', so that it will be looked up in the -  // AST file(s) if it is uttered in the source. This could save us some -  // module load time. -  SmallVector<IdentifierInfo *, 128> Identifiers; +  // Mark all of the identifiers in the identifier table as being out of date, +  // so that various accessors know to check the loaded modules when the +  // identifier is used.    for (IdentifierTable::iterator Id = PP.getIdentifierTable().begin(),                                IdEnd = PP.getIdentifierTable().end();         Id != IdEnd; ++Id) -    Identifiers.push_back(Id->second); -   -  for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) { -    IdentifierLookupVisitor Visitor(Identifiers[I]->getName()); -    ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); -  } +    Id->second->setOutOfDate(true);    InitializeContext(); @@ -4412,10 +4399,8 @@ void ASTReader::InitializeSema(Sema &S) {    // Makes sure any declarations that were deserialized "too early"    // still get added to the identifier's declaration chains.    for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { -    if (SemaObj->TUScope) -      SemaObj->TUScope->AddDecl(PreloadedDecls[I]); - -    SemaObj->IdResolver.AddDecl(PreloadedDecls[I]); +    SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I],  +                                       PreloadedDecls[I]->getDeclName());    }    PreloadedDecls.clear(); @@ -4446,7 +4431,10 @@ void ASTReader::InitializeSema(Sema &S) {  IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) {    IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart));    ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); -  return Visitor.getIdentifierInfo(); +  IdentifierInfo *II = Visitor.getIdentifierInfo(); +  if (II) +    II->setOutOfDate(false); +  return II;  }  namespace clang { @@ -4775,13 +4763,10 @@ ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,    for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {      NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));      if (SemaObj) { -      if (SemaObj->TUScope) { -        // Introduce this declaration into the translation-unit scope -        // and add it to the declaration chain for this identifier, so -        // that (unqualified) name lookup will find it. -        SemaObj->TUScope->AddDecl(D); -      } -      SemaObj->IdResolver.AddDeclToIdentifierChain(II, D); +      // Introduce this declaration into the translation-unit scope +      // and add it to the declaration chain for this identifier, so +      // that (unqualified) name lookup will find it. +      SemaObj->pushExternalDeclIntoScope(D, II);      } else {        // Queue this declaration so that it will be added to the        // translation unit scope and identifier's declaration chain diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index ba9a82bbb79..3f1a1d8ce89 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1664,8 +1664,9 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {      // chained PCH, by storing the offset into the original PCH rather than      // writing the macro definition a second time.      if (MI->isBuiltinMacro() || -        (Chain && Name->isFromAST() && MI->isFromAST() && -        !MI->hasChangedAfterLoad())) +        (Chain &&  +         Name->isFromAST() && !Name->hasChangedSinceDeserialization() &&  +         MI->isFromAST() && !MI->hasChangedAfterLoad()))        continue;      AddIdentifierRef(Name, Record); @@ -2191,6 +2192,7 @@ namespace {  class ASTIdentifierTableTrait {    ASTWriter &Writer;    Preprocessor &PP; +  IdentifierResolver &IdResolver;    bool IsModule;    /// \brief Determines whether this is an "interesting" identifier @@ -2200,6 +2202,7 @@ class ASTIdentifierTableTrait {      if (II->isPoisoned() ||          II->isExtensionToken() ||          II->getObjCOrBuiltinID() || +        II->hasRevertedTokenIDToIdentifier() ||          II->getFETokenInfo<void>())        return true; @@ -2223,15 +2226,16 @@ public:    typedef IdentID data_type;    typedef data_type data_type_ref; -  ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, bool IsModule) -    : Writer(Writer), PP(PP), IsModule(IsModule) { } +  ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP,  +                          IdentifierResolver &IdResolver, bool IsModule) +    : Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule) { }    static unsigned ComputeHash(const IdentifierInfo* II) {      return llvm::HashString(II->getName());    }    std::pair<unsigned,unsigned> -    EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) { +  EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {      unsigned KeyLen = II->getLength() + 1;      unsigned DataLen = 4; // 4 bytes for the persistent ID << 1      MacroInfo *Macro = 0; @@ -2239,8 +2243,9 @@ public:        DataLen += 2; // 2 bytes for builtin ID, flags        if (hasMacroDefinition(II, Macro))          DataLen += 4; -      for (IdentifierResolver::iterator D = IdentifierResolver::begin(II), -                                     DEnd = IdentifierResolver::end(); +       +      for (IdentifierResolver::iterator D = IdResolver.begin(II), +                                     DEnd = IdResolver.end();             D != DEnd; ++D)          DataLen += sizeof(DeclID);      } @@ -2285,14 +2290,13 @@ public:      // Emit the declaration IDs in reverse order, because the      // IdentifierResolver provides the declarations as they would be      // visible (e.g., the function "stat" would come before the struct -    // "stat"), but IdentifierResolver::AddDeclToIdentifierChain() -    // adds declarations to the end of the list (so we need to see the -    // struct "status" before the function "status"). +    // "stat"), but the ASTReader adds declarations to the end of the list  +    // (so we need to see the struct "status" before the function "status").      // Only emit declarations that aren't from a chained PCH, though. -    SmallVector<Decl *, 16> Decls(IdentifierResolver::begin(II), -                                        IdentifierResolver::end()); +    SmallVector<Decl *, 16> Decls(IdResolver.begin(II), +                                  IdResolver.end());      for (SmallVector<Decl *, 16>::reverse_iterator D = Decls.rbegin(), -                                                      DEnd = Decls.rend(); +                                                DEnd = Decls.rend();           D != DEnd; ++D)        clang::io::Emit32(Out, Writer.getDeclID(*D));    } @@ -2304,14 +2308,16 @@ public:  /// The identifier table consists of a blob containing string data  /// (the actual identifiers themselves) and a separate "offsets" index  /// that maps identifier IDs to locations within the blob. -void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) { +void ASTWriter::WriteIdentifierTable(Preprocessor &PP,  +                                     IdentifierResolver &IdResolver, +                                     bool IsModule) {    using namespace llvm;    // Create and write out the blob that contains the identifier    // strings.    {      OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator; -    ASTIdentifierTableTrait Trait(*this, PP, IsModule); +    ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);      // Look for any identifiers that were named while processing the      // headers, but are otherwise not needed. We add these to the hash @@ -2330,7 +2336,8 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) {             ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end();           ID != IDEnd; ++ID) {        assert(ID->first && "NULL identifier in identifier table"); -      if (!Chain || !ID->first->isFromAST()) +      if (!Chain || !ID->first->isFromAST() ||  +          ID->first->hasChangedSinceDeserialization())          Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,                            Trait);      } @@ -2339,7 +2346,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) {      llvm::SmallString<4096> IdentifierTable;      uint32_t BucketOffset;      { -      ASTIdentifierTableTrait Trait(*this, PP, IsModule); +      ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);        llvm::raw_svector_ostream Out(IdentifierTable);        // Make sure that no bucket is at offset 0        clang::io::Emit32(Out, 0); @@ -2791,6 +2798,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,        getIdentifierRef(&Table.get(BuiltinNames[I]));    } +  // If there are any out-of-date identifiers, bring them up to date. +  if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) { +    for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), +                                IDEnd = PP.getIdentifierTable().end(); +         ID != IDEnd; ++ID) +      if (ID->second->isOutOfDate()) +        ExtSource->updateOutOfDateIdentifier(*ID->second); +  } +    // Build a record containing all of the tentative definitions in this file, in    // TentativeDefinitions order.  Generally, this record will be empty for    // headers. @@ -3018,7 +3034,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,    WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);    WriteSelectors(SemaRef);    WriteReferencedSelectorsPool(SemaRef); -  WriteIdentifierTable(PP, IsModule); +  WriteIdentifierTable(PP, SemaRef.IdResolver, IsModule);    WriteFPPragmaOptions(SemaRef.getFPOptions());    WriteOpenCLExtensions(SemaRef); diff --git a/clang/test/Modules/redeclarations.m b/clang/test/Modules/redeclarations.m new file mode 100644 index 00000000000..1a37230fcc1 --- /dev/null +++ b/clang/test/Modules/redeclarations.m @@ -0,0 +1,22 @@ +#ifdef MODULE_LEFT +@class NSObject; +#endif + +#ifdef MODULE_RIGHT +@interface NSObject +@end +#endif + +#ifdef APP +__import_module__ Right; +__import_module__ Left; + +@interface MyObject : NSObject +@end +#endif + +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/Left.pcm -DMODULE_LEFT %s +// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -emit-module -o %t/Right.pcm -DMODULE_RIGHT %s +// RUN: %clang_cc1 -fmodule-cache-path %t -fdisable-module-hash -DAPP %s -verify +  | 

