From: Douglas Gregor Date: Wed, 15 Apr 2009 21:30:51 +0000 (+0000) Subject: PCH support for declaration attributes X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=68a2eb0cc76267ba0615992fb5e0977853c397b2;p=clang 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/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 158caa52d6..d8054de602 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -377,7 +377,12 @@ public: virtual ~NonNullAttr() { delete [] ArgNums; } - + + typedef const unsigned *iterator; + iterator begin() const { return ArgNums; } + iterator end() const { return ArgNums + Size; } + unsigned size() const { return Size; } + bool isNonNull(unsigned arg) const { return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true; } diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 252811bd59..4c619b0364 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -260,54 +260,59 @@ namespace clang { /// constant describes a record for a specific type class in the /// AST. enum TypeCode { + /// \brief Attributes attached to a type. + /// + /// Note that this has the same value as DECL_ATTR, since + /// attribute blocks are used for both types and declarations. + TYPE_ATTR = 1, /// \brief An ExtQualType record. - TYPE_EXT_QUAL = 1, + TYPE_EXT_QUAL = 2, /// \brief A FixedWidthIntType record. - TYPE_FIXED_WIDTH_INT = 2, + TYPE_FIXED_WIDTH_INT = 3, /// \brief A ComplexType record. - TYPE_COMPLEX = 3, + TYPE_COMPLEX = 4, /// \brief A PointerType record. - TYPE_POINTER = 4, + TYPE_POINTER = 5, /// \brief A BlockPointerType record. - TYPE_BLOCK_POINTER = 5, + TYPE_BLOCK_POINTER = 6, /// \brief An LValueReferenceType record. - TYPE_LVALUE_REFERENCE = 6, + TYPE_LVALUE_REFERENCE = 7, /// \brief An RValueReferenceType record. - TYPE_RVALUE_REFERENCE = 7, + TYPE_RVALUE_REFERENCE = 8, /// \brief A MemberPointerType record. - TYPE_MEMBER_POINTER = 8, + TYPE_MEMBER_POINTER = 9, /// \brief A ConstantArrayType record. - TYPE_CONSTANT_ARRAY = 9, + TYPE_CONSTANT_ARRAY = 10, /// \brief An IncompleteArrayType record. - TYPE_INCOMPLETE_ARRAY = 10, + TYPE_INCOMPLETE_ARRAY = 11, /// \brief A VariableArrayType record. - TYPE_VARIABLE_ARRAY = 11, + TYPE_VARIABLE_ARRAY = 12, /// \brief A VectorType record. - TYPE_VECTOR = 12, + TYPE_VECTOR = 13, /// \brief An ExtVectorType record. - TYPE_EXT_VECTOR = 13, + TYPE_EXT_VECTOR = 14, /// \brief A FunctionNoProtoType record. - TYPE_FUNCTION_NO_PROTO = 14, + TYPE_FUNCTION_NO_PROTO = 15, /// \brief A FunctionProtoType record. - TYPE_FUNCTION_PROTO = 15, + TYPE_FUNCTION_PROTO = 16, /// \brief A TypedefType record. - TYPE_TYPEDEF = 16, + TYPE_TYPEDEF = 17, /// \brief A TypeOfExprType record. - TYPE_TYPEOF_EXPR = 17, + TYPE_TYPEOF_EXPR = 18, /// \brief A TypeOfType record. - TYPE_TYPEOF = 18, + TYPE_TYPEOF = 19, /// \brief A RecordType record. - TYPE_RECORD = 19, + TYPE_RECORD = 20, /// \brief An EnumType record. - TYPE_ENUM = 20, + TYPE_ENUM = 21, /// \brief An ObjCInterfaceType record. - TYPE_OBJC_INTERFACE = 21, + TYPE_OBJC_INTERFACE = 22, /// \brief An ObjCQualifiedInterfaceType record. - TYPE_OBJC_QUALIFIED_INTERFACE = 22, + TYPE_OBJC_QUALIFIED_INTERFACE = 23, /// \brief An ObjCQualifiedIdType record. - TYPE_OBJC_QUALIFIED_ID = 23, + TYPE_OBJC_QUALIFIED_ID = 24, /// \brief An ObjCQualifiedClassType record. - TYPE_OBJC_QUALIFIED_CLASS = 24 + TYPE_OBJC_QUALIFIED_CLASS = 25 }; /// \brief Record codes for each kind of declaration. @@ -317,8 +322,13 @@ namespace clang { /// constant describes a record for a specific declaration class /// in the AST. enum DeclCode { + /// \brief Attributes attached to a declaration. + /// + /// Note that this has the same value as TYPE_ATTR, since + /// attribute blocks are used for both types and declarations. + DECL_ATTR = 1, /// \brief A TranslationUnitDecl record. - DECL_TRANSLATION_UNIT = 1, + DECL_TRANSLATION_UNIT, /// \brief A TypedefDecl record. DECL_TYPEDEF, /// \brief An EnumDecl record. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index e11c2edb10..4cc4c24cc5 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -37,6 +37,7 @@ namespace llvm { namespace clang { class ASTContext; +class Attr; class Decl; class DeclContext; class Preprocessor; @@ -225,6 +226,12 @@ public: /// \brief Read a floating-point value llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx); + // \brief Read a string + std::string ReadString(const RecordData &Record, unsigned &Idx); + + /// \brief Reads attributes from the current stream position. + Attr *ReadAttributes(); + /// \brief Reads an expression from the current stream position. Expr *ReadExpr(); diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index d95dc431c1..0f9031f1c1 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -118,6 +118,9 @@ private: uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); void WriteDeclsBlock(ASTContext &Context); void WriteIdentifierTable(); + void WriteAttributeRecord(const Attr *Attr); + + void AddString(const std::string &Str, RecordData &Record); public: /// \brief Create a new precompiled header writer that outputs to diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 983c2b8807..e5656d63f9 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -74,7 +74,8 @@ void PCHDeclReader::VisitDecl(Decl *D) { cast_or_null(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 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { 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 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { 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 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { 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 @@ llvm::APFloat PCHReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) { 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(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 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 46db1428e3..3fb7a1b3aa 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -276,7 +276,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) { Writer.AddDeclRef(cast_or_null(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 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) { 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 @@ void PCHWriter::WriteIdentifierTable() { 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(Attr)->getAliasee(), Record); + break; + + case Attr::Aligned: + Record.push_back(cast(Attr)->getAlignment()); + break; + + case Attr::AlwaysInline: + break; + + case Attr::AnalyzerNoReturn: + break; + + case Attr::Annotate: + AddString(cast(Attr)->getAnnotation(), Record); + break; + + case Attr::AsmLabel: + AddString(cast(Attr)->getLabel(), Record); + break; + + case Attr::Blocks: + Record.push_back(cast(Attr)->getType()); // FIXME: stable + break; + + case Attr::Cleanup: + AddDeclRef(cast(Attr)->getFunctionDecl(), Record); + break; + + case Attr::Const: + break; + + case Attr::Constructor: + Record.push_back(cast(Attr)->getPriority()); + break; + + case Attr::DLLExport: + case Attr::DLLImport: + case Attr::Deprecated: + break; + + case Attr::Destructor: + Record.push_back(cast(Attr)->getPriority()); + break; + + case Attr::FastCall: + break; + + case Attr::Format: { + const FormatAttr *Format = cast(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(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(Attr)->getAlignment()); + break; + + case Attr::Pure: + break; + + case Attr::Regparm: + Record.push_back(cast(Attr)->getNumParams()); + break; + + case Attr::Section: + AddString(cast(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(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) { } diff --git a/test/PCH/attrs.c b/test/PCH/attrs.c new file mode 100644 index 0000000000..57b92c035e --- /dev/null +++ b/test/PCH/attrs.c @@ -0,0 +1,8 @@ +// Test this without pch. +// RUN: clang-cc -include %S/attrs.h -fsyntax-only -verify %s + +// Test with pch. +// RUN: clang-cc -emit-pch -o %t %S/attrs.h && +// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s +// expected-note{{previous overload}} +double f(double); // expected-error{{overloadable}} diff --git a/test/PCH/attrs.h b/test/PCH/attrs.h new file mode 100644 index 0000000000..0d0156515c --- /dev/null +++ b/test/PCH/attrs.h @@ -0,0 +1,7 @@ +// Header for PCH test exprs.c + + + + + +int f(int) __attribute__((overloadable));