PCH support for declaration attributes

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69225 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 983c2b8..e5656d6 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -74,7 +74,8 @@
                      cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
   D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
   D->setInvalidDecl(Record[Idx++]);
-  // FIXME: hasAttrs
+  if (Record[Idx++])
+    D->addAttr(Reader.ReadAttributes());
   D->setImplicit(Record[Idx++]);
   D->setAccess((AccessSpecifier)Record[Idx++]);
 }
@@ -1074,6 +1075,10 @@
   RecordData Record;
   unsigned Code = Stream.ReadCode();
   switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) {
+  case pch::TYPE_ATTR:
+    assert(false && "Should never jump to an attribute block");
+    return QualType();
+
   case pch::TYPE_EXT_QUAL:
     // FIXME: Deserialize ExtQualType
     assert(false && "Cannot deserialize qualified types yet");
@@ -1264,6 +1269,12 @@
   PCHDeclReader Reader(*this, Record, Idx);
 
   switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) {
+  case pch::DECL_ATTR:
+  case pch::DECL_CONTEXT_LEXICAL:
+  case pch::DECL_CONTEXT_VISIBLE:
+    assert(false && "Record cannot be de-serialized with ReadDeclRecord");
+    break;
+
   case pch::DECL_TRANSLATION_UNIT:
     assert(Index == 0 && "Translation unit must be at index 0");
     Reader.VisitTranslationUnitDecl(Context.getTranslationUnitDecl());
@@ -1372,10 +1383,6 @@
     D = Block;
     break;
   }
-
-  default:
-    assert(false && "Cannot de-serialize this kind of declaration");
-    break;
   }
 
   // If this declaration is also a declaration context, get the
@@ -1635,6 +1642,146 @@
   return llvm::APFloat(ReadAPInt(Record, Idx));
 }
 
+// \brief Read a string
+std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) {
+  unsigned Len = Record[Idx++];
+  std::string Result(&Record[Idx], &Record[Idx] + Len);
+  Idx += Len;
+  return Result;
+}
+
+/// \brief Reads attributes from the current stream position.
+Attr *PCHReader::ReadAttributes() {
+  unsigned Code = Stream.ReadCode();
+  assert(Code == llvm::bitc::UNABBREV_RECORD && 
+         "Expected unabbreviated record"); (void)Code;
+  
+  RecordData Record;
+  unsigned Idx = 0;
+  unsigned RecCode = Stream.ReadRecord(Code, Record);
+  assert(RecCode == pch::DECL_ATTR && "Expected attribute record"); 
+  (void)RecCode;
+
+#define SIMPLE_ATTR(Name)                       \
+ case Attr::Name:                               \
+   New = ::new (Context) Name##Attr();          \
+   break
+
+#define STRING_ATTR(Name)                                       \
+ case Attr::Name:                                               \
+   New = ::new (Context) Name##Attr(ReadString(Record, Idx));   \
+   break
+
+#define UNSIGNED_ATTR(Name)                             \
+ case Attr::Name:                                       \
+   New = ::new (Context) Name##Attr(Record[Idx++]);     \
+   break
+
+  Attr *Attrs = 0;
+  while (Idx < Record.size()) {
+    Attr *New = 0;
+    Attr::Kind Kind = (Attr::Kind)Record[Idx++];
+    bool IsInherited = Record[Idx++];
+
+    switch (Kind) {
+    STRING_ATTR(Alias);
+    UNSIGNED_ATTR(Aligned);
+    SIMPLE_ATTR(AlwaysInline);
+    SIMPLE_ATTR(AnalyzerNoReturn);
+    STRING_ATTR(Annotate);
+    STRING_ATTR(AsmLabel);
+    
+    case Attr::Blocks:
+      New = ::new (Context) BlocksAttr(
+                                  (BlocksAttr::BlocksAttrTypes)Record[Idx++]);
+      break;
+      
+    case Attr::Cleanup:
+      New = ::new (Context) CleanupAttr(
+                                  cast<FunctionDecl>(GetDecl(Record[Idx++])));
+      break;
+
+    SIMPLE_ATTR(Const);
+    UNSIGNED_ATTR(Constructor);
+    SIMPLE_ATTR(DLLExport);
+    SIMPLE_ATTR(DLLImport);
+    SIMPLE_ATTR(Deprecated);
+    UNSIGNED_ATTR(Destructor);
+    SIMPLE_ATTR(FastCall);
+    
+    case Attr::Format: {
+      std::string Type = ReadString(Record, Idx);
+      unsigned FormatIdx = Record[Idx++];
+      unsigned FirstArg = Record[Idx++];
+      New = ::new (Context) FormatAttr(Type, FormatIdx, FirstArg);
+      break;
+    }
+
+    SIMPLE_ATTR(GNUCInline);
+    
+    case Attr::IBOutletKind:
+      New = ::new (Context) IBOutletAttr();
+      break;
+
+    SIMPLE_ATTR(NoReturn);
+    SIMPLE_ATTR(NoThrow);
+    SIMPLE_ATTR(Nodebug);
+    SIMPLE_ATTR(Noinline);
+    
+    case Attr::NonNull: {
+      unsigned Size = Record[Idx++];
+      llvm::SmallVector<unsigned, 16> ArgNums;
+      ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size);
+      Idx += Size;
+      New = ::new (Context) NonNullAttr(&ArgNums[0], Size);
+      break;
+    }
+
+    SIMPLE_ATTR(ObjCException);
+    SIMPLE_ATTR(ObjCNSObject);
+    SIMPLE_ATTR(Overloadable);
+    UNSIGNED_ATTR(Packed);
+    SIMPLE_ATTR(Pure);
+    UNSIGNED_ATTR(Regparm);
+    STRING_ATTR(Section);
+    SIMPLE_ATTR(StdCall);
+    SIMPLE_ATTR(TransparentUnion);
+    SIMPLE_ATTR(Unavailable);
+    SIMPLE_ATTR(Unused);
+    SIMPLE_ATTR(Used);
+    
+    case Attr::Visibility:
+      New = ::new (Context) VisibilityAttr(
+                              (VisibilityAttr::VisibilityTypes)Record[Idx++]);
+      break;
+
+    SIMPLE_ATTR(WarnUnusedResult);
+    SIMPLE_ATTR(Weak);
+    SIMPLE_ATTR(WeakImport);
+    }
+
+    assert(New && "Unable to decode attribute?");
+    New->setInherited(IsInherited);
+    New->setNext(Attrs);
+    Attrs = New;
+  }
+#undef UNSIGNED_ATTR
+#undef STRING_ATTR
+#undef SIMPLE_ATTR
+
+  // The list of attributes was built backwards. Reverse the list
+  // before returning it.
+  Attr *PrevAttr = 0, *NextAttr = 0;
+  while (Attrs) {
+    NextAttr = Attrs->getNext();
+    Attrs->setNext(PrevAttr);
+    PrevAttr = Attrs;
+    Attrs = NextAttr;
+  }
+
+  return PrevAttr;
+}
+
 Expr *PCHReader::ReadExpr() {
   // Within the bitstream, expressions are stored in Reverse Polish
   // Notation, with each of the subexpressions preceding the
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 46db142..3fb7a1b 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -276,7 +276,7 @@
   Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
   Writer.AddSourceLocation(D->getLocation(), Record);
   Record.push_back(D->isInvalidDecl());
-  // FIXME: hasAttrs
+  Record.push_back(D->hasAttrs());
   Record.push_back(D->isImplicit());
   Record.push_back(D->getAccess());
 }
@@ -1131,6 +1131,10 @@
     assert(W.Code && "Unhandled declaration kind while generating PCH");
     S.EmitRecord(W.Code, Record);
 
+    // If the declaration had any attributes, write them now.
+    if (D->hasAttrs())
+      WriteAttributeRecord(D->getAttrs());
+
     // Flush any expressions that were written as part of this declaration.
     FlushExprs();
     
@@ -1209,6 +1213,134 @@
   S.EmitRecord(pch::IDENTIFIER_OFFSET, IdentOffsets);
 }
 
+/// \brief Write a record containing the given attributes.
+void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
+  RecordData Record;
+  for (; Attr; Attr = Attr->getNext()) {
+    Record.push_back(Attr->getKind()); // FIXME: stable encoding
+    Record.push_back(Attr->isInherited());
+    switch (Attr->getKind()) {
+    case Attr::Alias:
+      AddString(cast<AliasAttr>(Attr)->getAliasee(), Record);
+      break;
+
+    case Attr::Aligned:
+      Record.push_back(cast<AlignedAttr>(Attr)->getAlignment());
+      break;
+
+    case Attr::AlwaysInline:
+      break;
+     
+    case Attr::AnalyzerNoReturn:
+      break;
+
+    case Attr::Annotate:
+      AddString(cast<AnnotateAttr>(Attr)->getAnnotation(), Record);
+      break;
+
+    case Attr::AsmLabel:
+      AddString(cast<AsmLabelAttr>(Attr)->getLabel(), Record);
+      break;
+
+    case Attr::Blocks:
+      Record.push_back(cast<BlocksAttr>(Attr)->getType()); // FIXME: stable
+      break;
+
+    case Attr::Cleanup:
+      AddDeclRef(cast<CleanupAttr>(Attr)->getFunctionDecl(), Record);
+      break;
+
+    case Attr::Const:
+      break;
+
+    case Attr::Constructor:
+      Record.push_back(cast<ConstructorAttr>(Attr)->getPriority());
+      break;
+
+    case Attr::DLLExport:
+    case Attr::DLLImport:
+    case Attr::Deprecated:
+      break;
+
+    case Attr::Destructor:
+      Record.push_back(cast<DestructorAttr>(Attr)->getPriority());
+      break;
+
+    case Attr::FastCall:
+      break;
+
+    case Attr::Format: {
+      const FormatAttr *Format = cast<FormatAttr>(Attr);
+      AddString(Format->getType(), Record);
+      Record.push_back(Format->getFormatIdx());
+      Record.push_back(Format->getFirstArg());
+      break;
+    }
+
+    case Attr::GNUCInline:
+    case Attr::IBOutletKind:
+    case Attr::NoReturn:
+    case Attr::NoThrow:
+    case Attr::Nodebug:
+    case Attr::Noinline:
+      break;
+
+    case Attr::NonNull: {
+      const NonNullAttr *NonNull = cast<NonNullAttr>(Attr);
+      Record.push_back(NonNull->size());
+      Record.insert(Record.end(), NonNull->begin(), NonNull->end());
+      break;
+    }
+
+    case Attr::ObjCException:
+    case Attr::ObjCNSObject:
+    case Attr::Overloadable:
+      break;
+
+    case Attr::Packed:
+      Record.push_back(cast<PackedAttr>(Attr)->getAlignment());
+      break;
+
+    case Attr::Pure:
+      break;
+
+    case Attr::Regparm:
+      Record.push_back(cast<RegparmAttr>(Attr)->getNumParams());
+      break;
+
+    case Attr::Section:
+      AddString(cast<SectionAttr>(Attr)->getName(), Record);
+      break;
+
+    case Attr::StdCall:
+    case Attr::TransparentUnion:
+    case Attr::Unavailable:
+    case Attr::Unused:
+    case Attr::Used:
+      break;
+
+    case Attr::Visibility:
+      // FIXME: stable encoding
+      Record.push_back(cast<VisibilityAttr>(Attr)->getVisibility()); 
+      break;
+
+    case Attr::WarnUnusedResult:
+    case Attr::Weak:
+    case Attr::WeakImport:
+      break;
+    }
+  }
+
+  assert((int)pch::DECL_ATTR == (int)pch::TYPE_ATTR && 
+         "DECL_ATTR/TYPE_ATTR mismatch");
+  S.EmitRecord(pch::DECL_ATTR, Record);
+}
+
+void PCHWriter::AddString(const std::string &Str, RecordData &Record) {
+  Record.push_back(Str.size());
+  Record.insert(Record.end(), Str.begin(), Str.end());
+}
+
 PCHWriter::PCHWriter(llvm::BitstreamWriter &S) 
   : S(S), NextTypeID(pch::NUM_PREDEF_TYPE_IDS) { }