PCH support for declaration attributes

llvm-svn: 69225
This commit is contained in:
Douglas Gregor 2009-04-15 21:30:51 +00:00
parent 617482c666
commit bc8a78d5a4
8 changed files with 351 additions and 32 deletions

View File

@ -377,7 +377,12 @@ public:
virtual ~NonNullAttr() { virtual ~NonNullAttr() {
delete [] ArgNums; 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 { bool isNonNull(unsigned arg) const {
return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true; return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
} }

View File

@ -260,54 +260,59 @@ namespace clang {
/// constant describes a record for a specific type class in the /// constant describes a record for a specific type class in the
/// AST. /// AST.
enum TypeCode { 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. /// \brief An ExtQualType record.
TYPE_EXT_QUAL = 1, TYPE_EXT_QUAL = 2,
/// \brief A FixedWidthIntType record. /// \brief A FixedWidthIntType record.
TYPE_FIXED_WIDTH_INT = 2, TYPE_FIXED_WIDTH_INT = 3,
/// \brief A ComplexType record. /// \brief A ComplexType record.
TYPE_COMPLEX = 3, TYPE_COMPLEX = 4,
/// \brief A PointerType record. /// \brief A PointerType record.
TYPE_POINTER = 4, TYPE_POINTER = 5,
/// \brief A BlockPointerType record. /// \brief A BlockPointerType record.
TYPE_BLOCK_POINTER = 5, TYPE_BLOCK_POINTER = 6,
/// \brief An LValueReferenceType record. /// \brief An LValueReferenceType record.
TYPE_LVALUE_REFERENCE = 6, TYPE_LVALUE_REFERENCE = 7,
/// \brief An RValueReferenceType record. /// \brief An RValueReferenceType record.
TYPE_RVALUE_REFERENCE = 7, TYPE_RVALUE_REFERENCE = 8,
/// \brief A MemberPointerType record. /// \brief A MemberPointerType record.
TYPE_MEMBER_POINTER = 8, TYPE_MEMBER_POINTER = 9,
/// \brief A ConstantArrayType record. /// \brief A ConstantArrayType record.
TYPE_CONSTANT_ARRAY = 9, TYPE_CONSTANT_ARRAY = 10,
/// \brief An IncompleteArrayType record. /// \brief An IncompleteArrayType record.
TYPE_INCOMPLETE_ARRAY = 10, TYPE_INCOMPLETE_ARRAY = 11,
/// \brief A VariableArrayType record. /// \brief A VariableArrayType record.
TYPE_VARIABLE_ARRAY = 11, TYPE_VARIABLE_ARRAY = 12,
/// \brief A VectorType record. /// \brief A VectorType record.
TYPE_VECTOR = 12, TYPE_VECTOR = 13,
/// \brief An ExtVectorType record. /// \brief An ExtVectorType record.
TYPE_EXT_VECTOR = 13, TYPE_EXT_VECTOR = 14,
/// \brief A FunctionNoProtoType record. /// \brief A FunctionNoProtoType record.
TYPE_FUNCTION_NO_PROTO = 14, TYPE_FUNCTION_NO_PROTO = 15,
/// \brief A FunctionProtoType record. /// \brief A FunctionProtoType record.
TYPE_FUNCTION_PROTO = 15, TYPE_FUNCTION_PROTO = 16,
/// \brief A TypedefType record. /// \brief A TypedefType record.
TYPE_TYPEDEF = 16, TYPE_TYPEDEF = 17,
/// \brief A TypeOfExprType record. /// \brief A TypeOfExprType record.
TYPE_TYPEOF_EXPR = 17, TYPE_TYPEOF_EXPR = 18,
/// \brief A TypeOfType record. /// \brief A TypeOfType record.
TYPE_TYPEOF = 18, TYPE_TYPEOF = 19,
/// \brief A RecordType record. /// \brief A RecordType record.
TYPE_RECORD = 19, TYPE_RECORD = 20,
/// \brief An EnumType record. /// \brief An EnumType record.
TYPE_ENUM = 20, TYPE_ENUM = 21,
/// \brief An ObjCInterfaceType record. /// \brief An ObjCInterfaceType record.
TYPE_OBJC_INTERFACE = 21, TYPE_OBJC_INTERFACE = 22,
/// \brief An ObjCQualifiedInterfaceType record. /// \brief An ObjCQualifiedInterfaceType record.
TYPE_OBJC_QUALIFIED_INTERFACE = 22, TYPE_OBJC_QUALIFIED_INTERFACE = 23,
/// \brief An ObjCQualifiedIdType record. /// \brief An ObjCQualifiedIdType record.
TYPE_OBJC_QUALIFIED_ID = 23, TYPE_OBJC_QUALIFIED_ID = 24,
/// \brief An ObjCQualifiedClassType record. /// \brief An ObjCQualifiedClassType record.
TYPE_OBJC_QUALIFIED_CLASS = 24 TYPE_OBJC_QUALIFIED_CLASS = 25
}; };
/// \brief Record codes for each kind of declaration. /// \brief Record codes for each kind of declaration.
@ -317,8 +322,13 @@ namespace clang {
/// constant describes a record for a specific declaration class /// constant describes a record for a specific declaration class
/// in the AST. /// in the AST.
enum DeclCode { 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. /// \brief A TranslationUnitDecl record.
DECL_TRANSLATION_UNIT = 1, DECL_TRANSLATION_UNIT,
/// \brief A TypedefDecl record. /// \brief A TypedefDecl record.
DECL_TYPEDEF, DECL_TYPEDEF,
/// \brief An EnumDecl record. /// \brief An EnumDecl record.

View File

@ -37,6 +37,7 @@ namespace llvm {
namespace clang { namespace clang {
class ASTContext; class ASTContext;
class Attr;
class Decl; class Decl;
class DeclContext; class DeclContext;
class Preprocessor; class Preprocessor;
@ -225,6 +226,12 @@ public:
/// \brief Read a floating-point value /// \brief Read a floating-point value
llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx); 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. /// \brief Reads an expression from the current stream position.
Expr *ReadExpr(); Expr *ReadExpr();

View File

@ -118,6 +118,9 @@ private:
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
void WriteDeclsBlock(ASTContext &Context); void WriteDeclsBlock(ASTContext &Context);
void WriteIdentifierTable(); void WriteIdentifierTable();
void WriteAttributeRecord(const Attr *Attr);
void AddString(const std::string &Str, RecordData &Record);
public: public:
/// \brief Create a new precompiled header writer that outputs to /// \brief Create a new precompiled header writer that outputs to

View File

@ -74,7 +74,8 @@ void PCHDeclReader::VisitDecl(Decl *D) {
cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++])));
D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++]));
D->setInvalidDecl(Record[Idx++]); D->setInvalidDecl(Record[Idx++]);
// FIXME: hasAttrs if (Record[Idx++])
D->addAttr(Reader.ReadAttributes());
D->setImplicit(Record[Idx++]); D->setImplicit(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]);
} }
@ -1074,6 +1075,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
RecordData Record; RecordData Record;
unsigned Code = Stream.ReadCode(); unsigned Code = Stream.ReadCode();
switch ((pch::TypeCode)Stream.ReadRecord(Code, Record)) { 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: case pch::TYPE_EXT_QUAL:
// FIXME: Deserialize ExtQualType // FIXME: Deserialize ExtQualType
assert(false && "Cannot deserialize qualified types yet"); assert(false && "Cannot deserialize qualified types yet");
@ -1264,6 +1269,12 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
PCHDeclReader Reader(*this, Record, Idx); PCHDeclReader Reader(*this, Record, Idx);
switch ((pch::DeclCode)Stream.ReadRecord(Code, Record)) { 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: case pch::DECL_TRANSLATION_UNIT:
assert(Index == 0 && "Translation unit must be at index 0"); assert(Index == 0 && "Translation unit must be at index 0");
Reader.VisitTranslationUnitDecl(Context.getTranslationUnitDecl()); Reader.VisitTranslationUnitDecl(Context.getTranslationUnitDecl());
@ -1372,10 +1383,6 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
D = Block; D = Block;
break; break;
} }
default:
assert(false && "Cannot de-serialize this kind of declaration");
break;
} }
// If this declaration is also a declaration context, get the // 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)); 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() { Expr *PCHReader::ReadExpr() {
// Within the bitstream, expressions are stored in Reverse Polish // Within the bitstream, expressions are stored in Reverse Polish
// Notation, with each of the subexpressions preceding the // Notation, with each of the subexpressions preceding the

View File

@ -276,7 +276,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) {
Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record); Writer.AddDeclRef(cast_or_null<Decl>(D->getLexicalDeclContext()), Record);
Writer.AddSourceLocation(D->getLocation(), Record); Writer.AddSourceLocation(D->getLocation(), Record);
Record.push_back(D->isInvalidDecl()); Record.push_back(D->isInvalidDecl());
// FIXME: hasAttrs Record.push_back(D->hasAttrs());
Record.push_back(D->isImplicit()); Record.push_back(D->isImplicit());
Record.push_back(D->getAccess()); Record.push_back(D->getAccess());
} }
@ -1131,6 +1131,10 @@ void PCHWriter::WriteDeclsBlock(ASTContext &Context) {
assert(W.Code && "Unhandled declaration kind while generating PCH"); assert(W.Code && "Unhandled declaration kind while generating PCH");
S.EmitRecord(W.Code, Record); 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. // Flush any expressions that were written as part of this declaration.
FlushExprs(); FlushExprs();
@ -1209,6 +1213,134 @@ void PCHWriter::WriteIdentifierTable() {
S.EmitRecord(pch::IDENTIFIER_OFFSET, IdentOffsets); 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) PCHWriter::PCHWriter(llvm::BitstreamWriter &S)
: S(S), NextTypeID(pch::NUM_PREDEF_TYPE_IDS) { } : S(S), NextTypeID(pch::NUM_PREDEF_TYPE_IDS) { }

8
clang/test/PCH/attrs.c Normal file
View File

@ -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}}

7
clang/test/PCH/attrs.h Normal file
View File

@ -0,0 +1,7 @@
// Header for PCH test exprs.c
int f(int) __attribute__((overloadable));