diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/AST/DeclBase.h | 30 | ||||
| -rw-r--r-- | clang/include/clang/Frontend/PCHBitCodes.h | 9 | ||||
| -rw-r--r-- | clang/include/clang/Frontend/PCHReader.h | 7 | ||||
| -rw-r--r-- | clang/include/clang/Frontend/PCHWriter.h | 11 | ||||
| -rw-r--r-- | clang/lib/Frontend/PCHReader.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/Frontend/PCHReaderDecl.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Frontend/PCHWriter.cpp | 22 | ||||
| -rw-r--r-- | clang/lib/Frontend/PCHWriterDecl.cpp | 32 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 17 | ||||
| -rw-r--r-- | clang/test/PCH/chain-predecl.h | 3 | ||||
| -rw-r--r-- | clang/test/PCH/chain-predecl.m | 16 | 
11 files changed, 139 insertions, 29 deletions
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 8a07475800f..3ff38dc0d58 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -222,11 +222,14 @@ protected:    // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum    unsigned Access : 2;    friend class CXXClassMemberWrapper; -   -  // PCHLevel - the "level" of precompiled header/AST file from which this -  // declaration was built. -  unsigned PCHLevel : 3; -   + +  /// PCHLevel - the "level" of precompiled header/AST file from which this +  /// declaration was built. +  unsigned PCHLevel : 2; + +  /// PCHChanged - if this declaration has changed since being deserialized +  bool PCHChanged : 1; +    /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.    unsigned IdentifierNamespace : 15; @@ -243,7 +246,7 @@ protected:      : NextDeclInContext(0), DeclCtx(DC),        Loc(L), DeclKind(DK), InvalidDecl(0),        HasAttrs(false), Implicit(false), Used(false), -      Access(AS_none), PCHLevel(0), +      Access(AS_none), PCHLevel(0), PCHChanged(false),        IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {      if (Decl::CollectingStats()) add(DK);    } @@ -251,7 +254,7 @@ protected:    Decl(Kind DK, EmptyShell Empty)      : NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),        HasAttrs(false), Implicit(false), Used(false), -      Access(AS_none), PCHLevel(0), +      Access(AS_none), PCHLevel(0), PCHChanged(false),        IdentifierNamespace(getIdentifierNamespaceForKind(DK)) {      if (Decl::CollectingStats()) add(DK);    } @@ -358,7 +361,7 @@ public:    unsigned getPCHLevel() const { return PCHLevel; }    /// \brief The maximum PCH level that any declaration may have. -  static const unsigned MaxPCHLevel = 7; +  static const unsigned MaxPCHLevel = 3;    /// \brief Set the PCH level of this declaration.    void setPCHLevel(unsigned Level) {  @@ -366,6 +369,17 @@ public:      PCHLevel = Level;    } +  /// \brief Query whether this declaration was changed in a significant way +  /// since being loaded from a PCH file. +  /// +  /// In an epic violation of layering, what is "significant" is entirely +  /// up to the PCH system, but implemented in AST and Sema. +  bool isChangedSinceDeserialization() const { return PCHChanged; } + +  /// \brief Mark this declaration as having changed since deserialization, or +  /// reset the flag. +  void setChangedSinceDeserialization(bool Changed) { PCHChanged = Changed; } +    unsigned getIdentifierNamespace() const {      return IdentifierNamespace;    } diff --git a/clang/include/clang/Frontend/PCHBitCodes.h b/clang/include/clang/Frontend/PCHBitCodes.h index 7605670f0ea..bce5c287e77 100644 --- a/clang/include/clang/Frontend/PCHBitCodes.h +++ b/clang/include/clang/Frontend/PCHBitCodes.h @@ -256,7 +256,14 @@ namespace clang {        WEAK_UNDECLARED_IDENTIFIERS = 31,        /// \brief Record code for pending implicit instantiations. -      PENDING_IMPLICIT_INSTANTIATIONS = 32 +      PENDING_IMPLICIT_INSTANTIATIONS = 32, + +      /// \brief Record code for a decl replacement block. +      /// +      /// If a declaration is modified after having been deserialized, and then +      /// written to a dependent PCH file, its ID and offset must be added to +      /// the replacement block. +      DECL_REPLACEMENTS = 33      };      /// \brief Record types used within a source manager block. diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 7be86050abf..906e3e1b221 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -321,6 +321,11 @@ private:    /// = I + 1 has already been loaded.    std::vector<Decl *> DeclsLoaded; +  typedef llvm::DenseMap<pch::DeclID, std::pair<PerFileData *, uint64_t> > +      DeclReplacementMap; +  /// \brief Declarations that have been replaced in a later file in the chain. +  DeclReplacementMap ReplacedDecls; +    /// \brief Information about the contents of a DeclContext.    struct DeclContextInfo {      llvm::BitstreamCursor *Stream; @@ -577,7 +582,7 @@ private:    RecordLocation TypeCursorForIndex(unsigned Index);    void LoadedDecl(unsigned Index, Decl *D);    Decl *ReadDeclRecord(unsigned Index, pch::DeclID ID); -  RecordLocation DeclCursorForIndex(unsigned Index); +  RecordLocation DeclCursorForIndex(unsigned Index, pch::DeclID ID);    void PassInterestingDeclsToConsumer(); diff --git a/clang/include/clang/Frontend/PCHWriter.h b/clang/include/clang/Frontend/PCHWriter.h index 11422b4ba22..bb083eaf8f8 100644 --- a/clang/include/clang/Frontend/PCHWriter.h +++ b/clang/include/clang/Frontend/PCHWriter.h @@ -227,10 +227,18 @@ private:    /// to this set, so that we can write out lexical content updates for it.    llvm::SmallPtrSet<const NamespaceDecl *, 16> UpdatedNamespaces; +  /// \brief Decls that have been replaced in the current dependent PCH. +  /// +  /// When a decl changes fundamentally after being deserialized (this shouldn't +  /// happen, but the ObjC AST nodes are designed this way), it will be +  /// serialized again. In this case, it is registered here, so that the reader +  /// knows to read the updated version. +  llvm::SmallVector<std::pair<pch::DeclID, uint64_t>, 16> ReplacedDecls; +    /// \brief Statements that we've encountered while serializing a    /// declaration or type.    llvm::SmallVector<Stmt *, 16> StmtsToEmit; -   +    /// \brief Statements collection to use for PCHWriter::AddStmt().    /// It will point to StmtsToEmit unless it is overriden.     llvm::SmallVector<Stmt *, 16> *CollectedStmts; @@ -274,6 +282,7 @@ private:    void WriteReferencedSelectorsPool(Sema &SemaRef);    void WriteIdentifierTable(Preprocessor &PP);    void WriteAttributeRecord(const Attr *Attr); +  void WriteDeclUpdateBlock();    unsigned ParmVarDeclAbbrev;    unsigned DeclContextLexicalAbbrev; diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index 16afabbb7e4..e55605b2743 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -1774,6 +1774,17 @@ PCHReader::ReadPCHBlock(PerFileData &F) {        F.NumPreallocatedPreprocessingEntities = Record[0];        F.LocalNumMacroDefinitions = Record[1];        break; + +    case pch::DECL_REPLACEMENTS: { +      if (Record.size() % 2 != 0) { +        Error("invalid DECL_REPLACEMENTS block in PCH file"); +        return Failure; +      } +      for (unsigned I = 0, N = Record.size(); I != N; I += 2) +        ReplacedDecls[static_cast<pch::DeclID>(Record[I])] = +            std::make_pair(&F, Record[I+1]); +      break; +    }      }      First = false;    } diff --git a/clang/lib/Frontend/PCHReaderDecl.cpp b/clang/lib/Frontend/PCHReaderDecl.cpp index 212eaa1332c..aa5ce7aad6a 100644 --- a/clang/lib/Frontend/PCHReaderDecl.cpp +++ b/clang/lib/Frontend/PCHReaderDecl.cpp @@ -1307,7 +1307,13 @@ static bool isConsumerInterestedIn(Decl *D) {  }  /// \brief Get the correct cursor and offset for loading a type. -PCHReader::RecordLocation PCHReader::DeclCursorForIndex(unsigned Index) { +PCHReader::RecordLocation +PCHReader::DeclCursorForIndex(unsigned Index, pch::DeclID ID) { +  // See if there's an override. +  DeclReplacementMap::iterator It = ReplacedDecls.find(ID); +  if (It != ReplacedDecls.end()) +    return RecordLocation(&It->second.first->DeclsCursor, It->second.second); +    PerFileData *F = 0;    for (unsigned I = 0, N = Chain.size(); I != N; ++I) {      F = Chain[N - I - 1]; @@ -1321,7 +1327,7 @@ PCHReader::RecordLocation PCHReader::DeclCursorForIndex(unsigned Index) {  /// \brief Read the declaration at the given offset from the PCH file.  Decl *PCHReader::ReadDeclRecord(unsigned Index, pch::DeclID ID) { -  RecordLocation Loc = DeclCursorForIndex(Index); +  RecordLocation Loc = DeclCursorForIndex(Index, ID);    llvm::BitstreamCursor &DeclsCursor = *Loc.first;    // Keep track of where we are in the stream, then jump back there    // after reading this declaration. diff --git a/clang/lib/Frontend/PCHWriter.cpp b/clang/lib/Frontend/PCHWriter.cpp index d7da4fc41ce..a86bdb9278d 100644 --- a/clang/lib/Frontend/PCHWriter.cpp +++ b/clang/lib/Frontend/PCHWriter.cpp @@ -2414,6 +2414,8 @@ void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,         I != E; ++I) {      if ((*I)->getPCHLevel() == 0)        NewGlobalDecls.push_back(GetDeclRef(*I)); +    else if ((*I)->isChangedSinceDeserialization()) +      (void)GetDeclRef(*I); // Make sure it's written, but don't record it.    }    // We also need to write a lexical updates block for the TU.    llvm::BitCodeAbbrev *Abv = new llvm::BitCodeAbbrev(); @@ -2596,10 +2598,24 @@ void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,    Record.push_back(NumMacros);    Record.push_back(NumLexicalDeclContexts);    Record.push_back(NumVisibleDeclContexts); +  WriteDeclUpdateBlock();    Stream.EmitRecord(pch::STATISTICS, Record);    Stream.ExitBlock();  } +void PCHWriter::WriteDeclUpdateBlock() { +  if (ReplacedDecls.empty()) +    return; + +  RecordData Record; +  for (llvm::SmallVector<std::pair<pch::DeclID, uint64_t>, 16>::iterator +           I = ReplacedDecls.begin(), E = ReplacedDecls.end(); I != E; ++I) { +    Record.push_back(I->first); +    Record.push_back(I->second); +  } +  Stream.EmitRecord(pch::DECL_REPLACEMENTS, Record); +} +  void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) {    Record.push_back(Loc.getRawEncoding());  } @@ -2817,6 +2833,12 @@ pch::DeclID PCHWriter::GetDeclRef(const Decl *D) {      // enqueue it in the list of declarations to emit.      ID = NextDeclID++;      DeclTypesToEmit.push(const_cast<Decl *>(D)); +  } else if (ID < FirstDeclID && D->isChangedSinceDeserialization()) { +    // We don't add it to the replacement collection here, because we don't +    // have the offset yet. +    DeclTypesToEmit.push(const_cast<Decl *>(D)); +    // Reset the flag, so that we don't add this decl multiple times. +    const_cast<Decl *>(D)->setChangedSinceDeserialization(false);    }    return ID; diff --git a/clang/lib/Frontend/PCHWriterDecl.cpp b/clang/lib/Frontend/PCHWriterDecl.cpp index 13e5239fe78..9893d254e9e 100644 --- a/clang/lib/Frontend/PCHWriterDecl.cpp +++ b/clang/lib/Frontend/PCHWriterDecl.cpp @@ -1126,18 +1126,24 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {    }    // Determine the ID for this declaration -  pch::DeclID &ID = DeclIDs[D]; -  if (ID == 0) -    ID = NextDeclID++; - -  unsigned Index = ID - FirstDeclID; - -  // Record the offset for this declaration -  if (DeclOffsets.size() == Index) -    DeclOffsets.push_back(Stream.GetCurrentBitNo()); -  else if (DeclOffsets.size() < Index) { -    DeclOffsets.resize(Index+1); -    DeclOffsets[Index] = Stream.GetCurrentBitNo(); +  pch::DeclID &IDR = DeclIDs[D]; +  if (IDR == 0) +    IDR = NextDeclID++; +  pch::DeclID ID = IDR; + +  if (ID < FirstDeclID) { +    // We're replacing a decl in a previous file. +    ReplacedDecls.push_back(std::make_pair(ID, Stream.GetCurrentBitNo())); +  } else { +    unsigned Index = ID - FirstDeclID; + +    // Record the offset for this declaration +    if (DeclOffsets.size() == Index) +      DeclOffsets.push_back(Stream.GetCurrentBitNo()); +    else if (DeclOffsets.size() < Index) { +      DeclOffsets.resize(Index+1); +      DeclOffsets[Index] = Stream.GetCurrentBitNo(); +    }    }    // Build and emit a record for this declaration @@ -1164,5 +1170,5 @@ void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) {    //    // FIXME: This should be renamed, the predicate is much more complicated.    if (isRequiredDecl(D, Context)) -    ExternalDefinitions.push_back(Index + 1); +    ExternalDefinitions.push_back(ID);  } diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index e98163e0c42..8bcb616285f 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -89,6 +89,9 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,        IDecl->setLocation(AtInterfaceLoc);        IDecl->setForwardDecl(false);        IDecl->setClassLoc(ClassLoc); +      // If the forward decl was in a PCH, we need to write it again in a +      // chained PCH. +      IDecl->setChangedSinceDeserialization(true);        // Since this ObjCInterfaceDecl was created by a forward declaration,        // we now add it to the DeclContext since it wasn't added before @@ -176,7 +179,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,      IDecl->setLocEnd(ClassLoc);    } -  /// Check then save referenced protocols. +  // Check then save referenced protocols.    if (NumProtoRefs) {      IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,                             ProtoLocs, Context); @@ -284,6 +287,9 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,      // Make sure the cached decl gets a valid start location.      PDecl->setLocation(AtProtoInterfaceLoc);      PDecl->setForwardDecl(false); +    CurContext->addDecl(PDecl); +    // Repeat in dependent PCHs. +    PDecl->setChangedSinceDeserialization(true);    } else {      PDecl = ObjCProtocolDecl::Create(Context, CurContext,                                       AtProtoInterfaceLoc,ProtocolName); @@ -384,13 +390,18 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,    for (unsigned i = 0; i != NumElts; ++i) {      IdentifierInfo *Ident = IdentList[i].first;      ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second); +    bool isNew = false;      if (PDecl == 0) { // Not already seen?        PDecl = ObjCProtocolDecl::Create(Context, CurContext,                                         IdentList[i].second, Ident); -      PushOnScopeChains(PDecl, TUScope); +      PushOnScopeChains(PDecl, TUScope, false); +      isNew = true;      } -    if (attrList) +    if (attrList) {        ProcessDeclAttributeList(TUScope, PDecl, attrList); +      if (!isNew) +        PDecl->setChangedSinceDeserialization(true); +    }      Protocols.push_back(PDecl);      ProtoLocs.push_back(IdentList[i].second);    } diff --git a/clang/test/PCH/chain-predecl.h b/clang/test/PCH/chain-predecl.h new file mode 100644 index 00000000000..bd332ff3ad0 --- /dev/null +++ b/clang/test/PCH/chain-predecl.h @@ -0,0 +1,3 @@ +// First header for chain-predecl.m +@class Foo; +@protocol Pro; diff --git a/clang/test/PCH/chain-predecl.m b/clang/test/PCH/chain-predecl.m new file mode 100644 index 00000000000..2b0444e15a2 --- /dev/null +++ b/clang/test/PCH/chain-predecl.m @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-pch -o %t1 %S/chain-predecl.h -x objective-c +// RUN: %clang_cc1 -emit-pch -o %t2 %s -x objective-c -include-pch %t1 -chained-pch + +// Test predeclarations across chained PCH. +@interface Foo +-(void)bar; +@end +@interface Boom +-(void)bar; +@end +@protocol Pro +-(void)baz; +@end +@protocol Kaboom +-(void)baz; +@end  | 

