[cfe-commits] r110125 - in /cfe/trunk: include/clang/AST/Redeclarable.h include/clang/Frontend/PCHBitCodes.h include/clang/Frontend/PCHReader.h include/clang/Frontend/PCHWriter.h lib/Frontend/PCHReader.cpp lib/Frontend/PCHReaderDecl.cpp lib/Frontend/PCHWriter.cpp lib/Frontend/PCHWriterDecl.cpp test/PCH/cxx-templates.cpp test/PCH/cxx-templates.h

Argyrios Kyrtzidis kyrtzidis at apple.com
Tue Aug 3 10:34:21 PDT 2010


Hi Sebastian, please review.

-Argiris

On Aug 3, 2010, at 6:30 PM, Argyrios Kyrtzidis wrote:

> Author: akirtzidis
> Date: Tue Aug  3 12:30:10 2010
> New Revision: 110125
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=110125&view=rev
> Log:
> Apart from storing/retrieving the previous redeclaration from PCH, also store/retrieve the most recent
> redeclaration. That way we are sure that the full redeclarations chain is loaded.
> 
> When using chained PCHs, first declarations point to the most recent redeclarations in the same PCH.
> To address this use a REDECLS_UPDATE_LATEST record block to keep track of which first declarations need
> to point to a most recent redeclaration in another PCH.
> 
> Modified:
>    cfe/trunk/include/clang/AST/Redeclarable.h
>    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
>    cfe/trunk/include/clang/Frontend/PCHReader.h
>    cfe/trunk/include/clang/Frontend/PCHWriter.h
>    cfe/trunk/lib/Frontend/PCHReader.cpp
>    cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
>    cfe/trunk/lib/Frontend/PCHWriter.cpp
>    cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
>    cfe/trunk/test/PCH/cxx-templates.cpp
>    cfe/trunk/test/PCH/cxx-templates.h
> 
> Modified: cfe/trunk/include/clang/AST/Redeclarable.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Redeclarable.h?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Redeclarable.h (original)
> +++ cfe/trunk/include/clang/AST/Redeclarable.h Tue Aug  3 12:30:10 2010
> @@ -177,6 +177,9 @@
>                                           static_cast<const decl_type*>(this)));
>   }
>   redecl_iterator redecls_end() const { return redecl_iterator(); }
> +
> +  friend class PCHDeclReader;
> +  friend class PCHDeclWriter;
> };
> 
> }
> 
> Modified: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (original)
> +++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Tue Aug  3 12:30:10 2010
> @@ -245,8 +245,12 @@
>       /// declarations.
>       TU_UPDATE_LEXICAL = 28,
> 
> +      /// \brief Record code for an update to first decls pointing to the
> +      /// latest redeclarations.
> +      REDECLS_UPDATE_LATEST = 29,
> +
>       /// \brief Record code for declarations that Sema keeps references of.
> -      SEMA_DECL_REFS = 29
> +      SEMA_DECL_REFS = 30
>     };
> 
>     /// \brief Record types used within a source manager block.
> 
> Modified: cfe/trunk/include/clang/Frontend/PCHReader.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHReader.h?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Frontend/PCHReader.h (original)
> +++ cfe/trunk/include/clang/Frontend/PCHReader.h Tue Aug  3 12:30:10 2010
> @@ -319,6 +319,11 @@
>   /// DeclContext.
>   DeclContextOffsetsMap DeclContextOffsets;
> 
> +  typedef llvm::DenseMap<pch::DeclID, pch::DeclID> FirstLatestDeclIDMap;
> +  /// \brief Map of first declarations from a chained PCH that point to the
> +  /// most recent declarations in another PCH.
> +  FirstLatestDeclIDMap FirstLatestDeclIDs;
> +
>   /// \brief Read the records that describe the contents of declcontexts.
>   bool ReadDeclContextStorage(llvm::BitstreamCursor &Cursor,
>                               const std::pair<uint64_t, uint64_t> &Offsets,
> @@ -561,7 +566,7 @@
>   QualType ReadTypeRecord(unsigned Index);
>   RecordLocation TypeCursorForIndex(unsigned Index);
>   void LoadedDecl(unsigned Index, Decl *D);
> -  Decl *ReadDeclRecord(unsigned Index);
> +  Decl *ReadDeclRecord(unsigned Index, pch::DeclID ID);
>   RecordLocation DeclCursorForIndex(unsigned Index);
> 
>   void PassInterestingDeclsToConsumer();
> 
> Modified: cfe/trunk/include/clang/Frontend/PCHWriter.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHWriter.h?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Frontend/PCHWriter.h (original)
> +++ cfe/trunk/include/clang/Frontend/PCHWriter.h Tue Aug  3 12:30:10 2010
> @@ -79,6 +79,7 @@
> public:
>   typedef llvm::SmallVector<uint64_t, 64> RecordData;
> 
> +  friend class PCHDeclWriter;
> private:
>   /// \brief The bitstream writer used to emit this precompiled header.
>   llvm::BitstreamWriter &Stream;
> @@ -195,6 +196,11 @@
>   /// \brief Mapping from the macro definition indices in \c MacroDefinitions
>   /// to the corresponding offsets within the preprocessor block.
>   std::vector<uint32_t> MacroDefinitionOffsets;
> +
> +  typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap;
> +  /// \brief Map of first declarations from a chained PCH that point to the
> +  /// most recent declarations in another PCH.
> +  FirstLatestDeclMap FirstLatestDecls;
> 
>   /// \brief Declarations encountered that might be external
>   /// definitions.
> 
> Modified: cfe/trunk/lib/Frontend/PCHReader.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReader.cpp?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/PCHReader.cpp (original)
> +++ cfe/trunk/lib/Frontend/PCHReader.cpp Tue Aug  3 12:30:10 2010
> @@ -1557,6 +1557,18 @@
>       break;
>     }
> 
> +    case pch::REDECLS_UPDATE_LATEST: {
> +      assert(Record.size() % 2 == 0 && "Expected pairs of DeclIDs");
> +      for (unsigned i = 0, e = Record.size(); i < e; i += 2) {
> +        pch::DeclID First = Record[i], Latest = Record[i+1];
> +        assert((FirstLatestDeclIDs.find(First) == FirstLatestDeclIDs.end() ||
> +                Latest > FirstLatestDeclIDs[First]) &&
> +               "The new latest is supposed to come after the previous latest");
> +        FirstLatestDeclIDs[First] = Latest;
> +      }
> +      break;
> +    }
> +
>     case pch::LANGUAGE_OPTIONS:
>       if (ParseLanguageOptions(Record) && !DisableValidation)
>         return IgnorePCH;
> @@ -2868,7 +2880,7 @@
> 
> TranslationUnitDecl *PCHReader::GetTranslationUnitDecl() {
>   if (!DeclsLoaded[0]) {
> -    ReadDeclRecord(0);
> +    ReadDeclRecord(0, 0);
>     if (DeserializationListener)
>       DeserializationListener->DeclRead(1, DeclsLoaded[0]);
>   }
> @@ -2887,7 +2899,7 @@
> 
>   unsigned Index = ID - 1;
>   if (!DeclsLoaded[Index]) {
> -    ReadDeclRecord(Index);
> +    ReadDeclRecord(Index, ID);
>     if (DeserializationListener)
>       DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
>   }
> 
> Modified: cfe/trunk/lib/Frontend/PCHReaderDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderDecl.cpp?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/PCHReaderDecl.cpp (original)
> +++ cfe/trunk/lib/Frontend/PCHReaderDecl.cpp Tue Aug  3 12:30:10 2010
> @@ -31,6 +31,7 @@
>   class PCHDeclReader : public DeclVisitor<PCHDeclReader, void> {
>     PCHReader &Reader;
>     llvm::BitstreamCursor &Cursor;
> +    const pch::DeclID ThisDeclID;
>     const PCHReader::RecordData &Record;
>     unsigned &Idx;
>     pch::TypeID TypeIDForTypeDecl;
> @@ -39,9 +40,10 @@
> 
>   public:
>     PCHDeclReader(PCHReader &Reader, llvm::BitstreamCursor &Cursor,
> -                  const PCHReader::RecordData &Record, unsigned &Idx)
> -      : Reader(Reader), Cursor(Cursor), Record(Record), Idx(Idx),
> -        TypeIDForTypeDecl(0) { }
> +                  pch::DeclID thisDeclID, const PCHReader::RecordData &Record,
> +                  unsigned &Idx)
> +      : Reader(Reader), Cursor(Cursor), ThisDeclID(thisDeclID), Record(Record),
> +        Idx(Idx), TypeIDForTypeDecl(0) { }
> 
>     void Visit(Decl *D);
> 
> @@ -93,6 +95,7 @@
>     void VisitBlockDecl(BlockDecl *BD);
> 
>     std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
> +    template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
> 
>     // FIXME: Reorder according to DeclNodes.td?
>     void VisitObjCMethodDecl(ObjCMethodDecl *D);
> @@ -178,8 +181,7 @@
> void PCHDeclReader::VisitTagDecl(TagDecl *TD) {
>   VisitTypeDecl(TD);
>   TD->IdentifierNamespace = Record[Idx++];
> -  TD->setPreviousDeclaration(
> -                        cast_or_null<TagDecl>(Reader.GetDecl(Record[Idx++])));
> +  VisitRedeclarable(TD);
>   TD->setTagKind((TagDecl::TagKind)Record[Idx++]);
>   TD->setDefinition(Record[Idx++]);
>   TD->setEmbeddedInDeclarator(Record[Idx++]);
> @@ -305,10 +307,7 @@
>   // FunctionDecl's body is handled last at PCHReaderDecl::Visit,
>   // after everything else is read.
> 
> -  // Avoid side effects and invariant checking of FunctionDecl's
> -  // setPreviousDeclaration.
> -  FD->redeclarable_base::setPreviousDeclaration(
> -                   cast_or_null<FunctionDecl>(Reader.GetDecl(Record[Idx++])));
> +  VisitRedeclarable(FD);
>   FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]);
>   FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]);
>   FD->setInlineSpecified(Record[Idx++]);
> @@ -550,8 +549,7 @@
>   VD->setDeclaredInCondition(Record[Idx++]);
>   VD->setExceptionVariable(Record[Idx++]);
>   VD->setNRVOVariable(Record[Idx++]);
> -  VD->setPreviousDeclaration(
> -                         cast_or_null<VarDecl>(Reader.GetDecl(Record[Idx++])));
> +  VisitRedeclarable(VD);
>   if (Record[Idx++])
>     VD->setInit(Reader.ReadExpr(Cursor));
> 
> @@ -918,6 +916,25 @@
> 
>     RedeclarableTemplateDecl *LatestDecl = 
>         cast_or_null<RedeclarableTemplateDecl>(Reader.GetDecl(Record[Idx++]));
> +  
> +    // This decl is a first one and the latest declaration that it points to is
> +    // in the same PCH. However, if this actually needs to point to a
> +    // redeclaration in another chained PCH, we need to update it by checking
> +    // the FirstLatestDeclIDs map which tracks this kind of decls.
> +    assert(Reader.GetDecl(ThisDeclID) == D && "Invalid ThisDeclID ?");
> +    PCHReader::FirstLatestDeclIDMap::iterator I
> +        = Reader.FirstLatestDeclIDs.find(ThisDeclID);
> +    if (I != Reader.FirstLatestDeclIDs.end()) {
> +      Decl *NewLatest = Reader.GetDecl(I->second);
> +      assert((LatestDecl->getLocation().isInvalid() ||
> +              NewLatest->getLocation().isInvalid()  ||
> +              Reader.SourceMgr.isBeforeInTranslationUnit(
> +                                                   LatestDecl->getLocation(),
> +                                                   NewLatest->getLocation())) &&
> +             "The new latest is supposed to come after the previous latest");
> +      LatestDecl = cast<RedeclarableTemplateDecl>(NewLatest);
> +    }
> +
>     assert(LatestDecl->getKind() == D->getKind() && "Latest kind mismatch");
>     D->getCommonPtr()->Latest = LatestDecl;
>   }
> @@ -1072,6 +1089,54 @@
>   return std::make_pair(LexicalOffset, VisibleOffset);
> }
> 
> +template <typename T>
> +void PCHDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
> +  enum RedeclKind { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
> +  RedeclKind Kind = (RedeclKind)Record[Idx++];
> +  switch (Kind) {
> +  default:
> +    assert(0 && "Out of sync with PCHDeclWriter::VisitRedeclarable or messed up"
> +                " reading");
> +  case NoRedeclaration:
> +    break;
> +  case PointsToPrevious:
> +    D->RedeclLink = typename Redeclarable<T>::PreviousDeclLink(
> +                                cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
> +    break;
> +  case PointsToLatest:
> +    D->RedeclLink = typename Redeclarable<T>::LatestDeclLink(
> +                                cast_or_null<T>(Reader.GetDecl(Record[Idx++])));
> +    break;
> +  }
> +
> +  assert(!(Kind == PointsToPrevious &&
> +           Reader.FirstLatestDeclIDs.find(ThisDeclID) !=
> +               Reader.FirstLatestDeclIDs.end()) &&
> +         "This decl is not first, it should not be in the map");
> +  if (Kind == PointsToPrevious)
> +    return;
> +
> +  // This decl is a first one and the latest declaration that it points to is in
> +  // the same PCH. However, if this actually needs to point to a redeclaration
> +  // in another chained PCH, we need to update it by checking the
> +  // FirstLatestDeclIDs map which tracks this kind of decls.
> +  assert(Reader.GetDecl(ThisDeclID) == static_cast<T*>(D) &&
> +         "Invalid ThisDeclID ?");
> +  PCHReader::FirstLatestDeclIDMap::iterator I
> +      = Reader.FirstLatestDeclIDs.find(ThisDeclID);
> +  if (I != Reader.FirstLatestDeclIDs.end()) {
> +    Decl *NewLatest = Reader.GetDecl(I->second);
> +    assert((D->getMostRecentDeclaration()->getLocation().isInvalid() ||
> +            NewLatest->getLocation().isInvalid() ||
> +            Reader.SourceMgr.isBeforeInTranslationUnit(
> +                                   D->getMostRecentDeclaration()->getLocation(),
> +                                   NewLatest->getLocation())) &&
> +           "The new latest is supposed to come after the previous latest");
> +    D->RedeclLink
> +        = typename Redeclarable<T>::LatestDeclLink(cast_or_null<T>(NewLatest));
> +  }
> +}
> +
> //===----------------------------------------------------------------------===//
> // Attribute Reading
> //===----------------------------------------------------------------------===//
> @@ -1304,7 +1369,7 @@
> }
> 
> /// \brief Read the declaration at the given offset from the PCH file.
> -Decl *PCHReader::ReadDeclRecord(unsigned Index) {
> +Decl *PCHReader::ReadDeclRecord(unsigned Index, pch::DeclID ID) {
>   RecordLocation Loc = DeclCursorForIndex(Index);
>   llvm::BitstreamCursor &DeclsCursor = *Loc.first;
>   // Keep track of where we are in the stream, then jump back there
> @@ -1320,7 +1385,7 @@
>   RecordData Record;
>   unsigned Code = DeclsCursor.ReadCode();
>   unsigned Idx = 0;
> -  PCHDeclReader Reader(*this, DeclsCursor, Record, Idx);
> +  PCHDeclReader Reader(*this, DeclsCursor, ID, Record, Idx);
> 
>   Decl *D = 0;
>   switch ((pch::DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
> 
> Modified: cfe/trunk/lib/Frontend/PCHWriter.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriter.cpp?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/PCHWriter.cpp (original)
> +++ cfe/trunk/lib/Frontend/PCHWriter.cpp Tue Aug  3 12:30:10 2010
> @@ -2410,6 +2410,19 @@
>   WriteIdentifierTable(PP);
>   WriteTypeDeclOffsets();
> 
> +  /// Build a record containing first declarations from a chained PCH and the
> +  /// most recent declarations in this PCH that they point to.
> +  RecordData FirstLatestDeclIDs;
> +  for (FirstLatestDeclMap::iterator
> +        I = FirstLatestDecls.begin(), E = FirstLatestDecls.end(); I != E; ++I) {
> +    assert(I->first->getPCHLevel() > I->second->getPCHLevel() &&
> +           "Expected first & second to be in different PCHs");
> +    AddDeclRef(I->first, FirstLatestDeclIDs);
> +    AddDeclRef(I->second, FirstLatestDeclIDs);
> +  }
> +  if (!FirstLatestDeclIDs.empty())
> +    Stream.EmitRecord(pch::REDECLS_UPDATE_LATEST, FirstLatestDeclIDs);
> +
>   // Write the record containing external, unnamed definitions.
>   if (!ExternalDefinitions.empty())
>     Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions);
> 
> Modified: cfe/trunk/lib/Frontend/PCHWriterDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterDecl.cpp?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/PCHWriterDecl.cpp (original)
> +++ cfe/trunk/lib/Frontend/PCHWriterDecl.cpp Tue Aug  3 12:30:10 2010
> @@ -92,6 +92,7 @@
> 
>     void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
>                           uint64_t VisibleOffset);
> +    template <typename T> void VisitRedeclarable(Redeclarable<T> *D);
> 
> 
>     // FIXME: Put in the same order is DeclNodes.td?
> @@ -163,7 +164,7 @@
> void PCHDeclWriter::VisitTagDecl(TagDecl *D) {
>   VisitTypeDecl(D);
>   Record.push_back(D->getIdentifierNamespace());
> -  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
> +  VisitRedeclarable(D);
>   Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding
>   Record.push_back(D->isDefinition());
>   Record.push_back(D->isEmbeddedInDeclarator());
> @@ -279,7 +280,7 @@
>   // FunctionDecl's body is handled last at PCHWriterDecl::Visit,
>   // after everything else is written.
> 
> -  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
> +  VisitRedeclarable(D);
>   Record.push_back(D->getStorageClass()); // FIXME: stable encoding
>   Record.push_back(D->getStorageClassAsWritten());
>   Record.push_back(D->isInlineSpecified());
> @@ -500,7 +501,7 @@
>   Record.push_back(D->isDeclaredInCondition());
>   Record.push_back(D->isExceptionVariable());
>   Record.push_back(D->isNRVOVariable());
> -  Writer.AddDeclRef(D->getPreviousDeclaration(), Record);
> +  VisitRedeclarable(D);
>   Record.push_back(D->getInit() ? 1 : 0);
>   if (D->getInit())
>     Writer.AddStmt(D->getInit());
> @@ -854,6 +855,18 @@
>       Record.push_back(D->isMemberSpecialization());
> 
>     Writer.AddDeclRef(D->getCommonPtr()->Latest, Record);
> +  } else {
> +    RedeclarableTemplateDecl *First = D->getFirstDeclaration();
> +    assert(First != D);
> +    // If this is a most recent redeclaration that is pointed to by a first decl
> +    // in a chained PCH, keep track of the association with the map so we can
> +    // update the first decl during PCH reading.
> +    if (First->getMostRecentDeclaration() == D &&
> +        First->getPCHLevel() > D->getPCHLevel()) {
> +      assert(Writer.FirstLatestDecls.find(First)==Writer.FirstLatestDecls.end()
> +             && "The latest is already set");
> +      Writer.FirstLatestDecls[First] = D;
> +    }
>   }
> }
> 
> @@ -1016,6 +1029,29 @@
>   Record.push_back(VisibleOffset);
> }
> 
> +template <typename T>
> +void PCHDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
> +  enum { NoRedeclaration = 0, PointsToPrevious, PointsToLatest };
> +  if (D->RedeclLink.getNext() == D) {
> +    Record.push_back(NoRedeclaration);
> +  } else {
> +    Record.push_back(D->RedeclLink.NextIsPrevious() ? PointsToPrevious
> +                                                    : PointsToLatest);
> +    Writer.AddDeclRef(D->RedeclLink.getPointer(), Record);
> +  }
> +
> +  T *First = D->getFirstDeclaration();
> +  T *ThisDecl = static_cast<T*>(D);
> +  // If this is a most recent redeclaration that is pointed to by a first decl
> +  // in a chained PCH, keep track of the association with the map so we can
> +  // update the first decl during PCH reading.
> +  if (ThisDecl != First && First->getMostRecentDeclaration() == ThisDecl &&
> +      First->getPCHLevel() > ThisDecl->getPCHLevel()) {
> +    assert(Writer.FirstLatestDecls.find(First) == Writer.FirstLatestDecls.end()
> +           && "The latest is already set");
> +    Writer.FirstLatestDecls[First] = ThisDecl;
> +  }
> +}
> 
> //===----------------------------------------------------------------------===//
> // PCHWriter Implementation
> 
> Modified: cfe/trunk/test/PCH/cxx-templates.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-templates.cpp?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/test/PCH/cxx-templates.cpp (original)
> +++ cfe/trunk/test/PCH/cxx-templates.cpp Tue Aug  3 12:30:10 2010
> @@ -1,9 +1,13 @@
> // Test this without pch.
> -// RUN: %clang_cc1 -include %S/cxx-templates.h -verify %s -ast-dump
> +// RUN: %clang_cc1 -include %S/cxx-templates.h -verify %s -ast-dump 1>/dev/null
> +// RUN: %clang_cc1 -include %S/cxx-templates.h %s -emit-llvm -o - | FileCheck %s
> 
> // Test with pch.
> // RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-templates.h
> -// RUN: %clang_cc1 -include-pch %t -verify %s -ast-dump 
> +// RUN: %clang_cc1 -include-pch %t -verify %s -ast-dump  1>/dev/null
> +// RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s
> +
> +// CHECK: define linkonce_odr void @_ZN2S3IiE1mEv
> 
> struct A {
>   typedef int type;
> @@ -22,4 +26,7 @@
>   Dep<A>::Ty ty;
>   Dep<A> a;
>   a.f();
> +  
> +  S3<int> s3;
> +  s3.m();
> }
> 
> Modified: cfe/trunk/test/PCH/cxx-templates.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-templates.h?rev=110125&r1=110124&r2=110125&view=diff
> ==============================================================================
> --- cfe/trunk/test/PCH/cxx-templates.h (original)
> +++ cfe/trunk/test/PCH/cxx-templates.h Tue Aug  3 12:30:10 2010
> @@ -116,3 +116,11 @@
> };
> 
> extern template class S2<true>;
> +
> +template <typename T>
> +struct S3 {
> +    void m();
> +};
> +
> +template <typename T>
> +inline void S3<T>::m() { }
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits





More information about the cfe-commits mailing list