forked from OSchip/llvm-project
Add PCH read/write support for Objective-C Selectors.
Note: This support is non-lazy. Once we get "Cocoa.h" humming, we can optimize this. llvm-svn: 69884
This commit is contained in:
parent
5058f240d9
commit
2ddea05bca
|
@ -370,7 +370,6 @@ class Selector {
|
|||
InfoPtr = reinterpret_cast<uintptr_t>(SI);
|
||||
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
|
||||
}
|
||||
Selector(uintptr_t V) : InfoPtr(V) {}
|
||||
|
||||
IdentifierInfo *getAsIdentifierInfo() const {
|
||||
if (getIdentifierInfoFlag())
|
||||
|
@ -388,6 +387,7 @@ public:
|
|||
/// The default ctor should only be used when creating data structures that
|
||||
/// will contain selectors.
|
||||
Selector() : InfoPtr(0) {}
|
||||
Selector(uintptr_t V) : InfoPtr(V) {}
|
||||
|
||||
/// operator==/!= - Indicate whether the specified selectors are identical.
|
||||
bool operator==(Selector RHS) const {
|
||||
|
|
|
@ -45,6 +45,8 @@ namespace clang {
|
|||
/// file.
|
||||
typedef uint32_t IdentID;
|
||||
|
||||
typedef uint32_t SelectorID;
|
||||
|
||||
/// \brief Describes the various kinds of blocks that occur within
|
||||
/// a PCH file.
|
||||
enum BlockIDs {
|
||||
|
@ -66,7 +68,10 @@ namespace clang {
|
|||
|
||||
/// \brief The block containing the definitions of all of the
|
||||
/// declarations stored in the PCH file.
|
||||
DECLS_BLOCK_ID
|
||||
DECLS_BLOCK_ID,
|
||||
|
||||
/// \brief The block containing ObjC selectors stored in the PCH file.
|
||||
SELECTOR_BLOCK_ID
|
||||
};
|
||||
|
||||
/// \brief Record types that occur within the PCH block itself.
|
||||
|
@ -160,7 +165,10 @@ namespace clang {
|
|||
|
||||
/// \brief Record code for the array of locally-scoped external
|
||||
/// declarations.
|
||||
LOCALLY_SCOPED_EXTERNAL_DECLS = 11
|
||||
LOCALLY_SCOPED_EXTERNAL_DECLS = 11,
|
||||
|
||||
/// \brief Record code for the Objective-C Selector Table.
|
||||
SELECTOR_TABLE = 12
|
||||
};
|
||||
|
||||
/// \brief Record types used within a source manager block.
|
||||
|
|
|
@ -145,6 +145,9 @@ private:
|
|||
/// an IdentifierInfo* that has already been resolved.
|
||||
llvm::SmallVector<uint64_t, 16> IdentifierData;
|
||||
|
||||
/// \brief SelectorData, indexed by the selector ID minus one.
|
||||
llvm::SmallVector<Selector, 16> SelectorData;
|
||||
|
||||
/// \brief The set of external definitions stored in the the PCH
|
||||
/// file.
|
||||
llvm::SmallVector<uint64_t, 16> ExternalDefinitions;
|
||||
|
@ -198,13 +201,15 @@ private:
|
|||
/// \brief FIXME: document!
|
||||
llvm::SmallVector<uint64_t, 4> SpecialTypes;
|
||||
|
||||
PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset);
|
||||
PCHReadResult ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
|
||||
uint64_t &SelectorBlockOffset);
|
||||
bool CheckPredefinesBuffer(const char *PCHPredef,
|
||||
unsigned PCHPredefLen,
|
||||
FileID PCHBufferID);
|
||||
PCHReadResult ReadSourceManagerBlock();
|
||||
bool ReadPreprocessorBlock();
|
||||
|
||||
bool ReadSelectorBlock();
|
||||
|
||||
bool ParseLanguageOptions(const llvm::SmallVectorImpl<uint64_t> &Record);
|
||||
QualType ReadTypeRecord(uint64_t Offset);
|
||||
void LoadedDecl(unsigned Index, Decl *D);
|
||||
|
@ -313,6 +318,12 @@ public:
|
|||
IdentifierInfo *GetIdentifierInfo(const RecordData &Record, unsigned &Idx) {
|
||||
return DecodeIdentifierInfo(Record[Idx++]);
|
||||
}
|
||||
|
||||
Selector DecodeSelector(unsigned Idx);
|
||||
|
||||
Selector GetSelector(const RecordData &Record, unsigned &Idx) {
|
||||
return DecodeSelector(Record[Idx++]);
|
||||
}
|
||||
DeclarationName ReadDeclarationName(const RecordData &Record, unsigned &Idx);
|
||||
|
||||
/// \brief Read an integral value
|
||||
|
|
|
@ -93,11 +93,17 @@ private:
|
|||
/// discovery), starting at 1. An ID of zero refers to a NULL
|
||||
/// IdentifierInfo.
|
||||
llvm::DenseMap<const IdentifierInfo *, pch::IdentID> IdentifierIDs;
|
||||
|
||||
|
||||
/// \brief Offsets of each of the identifier IDs into the identifier
|
||||
/// table, shifted left by one bit with the low bit set.
|
||||
llvm::SmallVector<uint64_t, 16> IdentifierOffsets;
|
||||
|
||||
/// \brief Map that provides the ID numbers of each Selector.
|
||||
llvm::DenseMap<Selector, pch::SelectorID> SelectorIDs;
|
||||
|
||||
/// \brief A vector of all Selectors (ordered by ID).
|
||||
llvm::SmallVector<Selector, 16> SelVector;
|
||||
|
||||
/// \brief Offsets of each of the macro identifiers into the
|
||||
/// bitstream.
|
||||
///
|
||||
|
@ -154,6 +160,7 @@ private:
|
|||
uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
|
||||
void WriteDeclsBlock(ASTContext &Context);
|
||||
void WriteIdentifierTable(Preprocessor &PP);
|
||||
void WriteSelectorTable();
|
||||
void WriteAttributeRecord(const Attr *Attr);
|
||||
|
||||
public:
|
||||
|
@ -179,6 +186,9 @@ public:
|
|||
/// \brief Emit a reference to an identifier
|
||||
void AddIdentifierRef(const IdentifierInfo *II, RecordData &Record);
|
||||
|
||||
/// \brief Emit a Selector (which is a smart pointer reference)
|
||||
void AddSelectorRef(const Selector, RecordData &Record);
|
||||
|
||||
/// \brief Get the unique number used to refer to the given
|
||||
/// identifier.
|
||||
pch::IdentID getIdentifierRef(const IdentifierInfo *II);
|
||||
|
|
|
@ -1063,7 +1063,7 @@ unsigned PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
|
|||
|
||||
unsigned PCHStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
||||
VisitExpr(E);
|
||||
// FIXME: Selectors.
|
||||
E->setSelector(Reader.GetSelector(Record, Idx));
|
||||
E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||
E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||
return 0;
|
||||
|
@ -1586,8 +1586,69 @@ bool PCHReader::ReadPreprocessorBlock() {
|
|||
}
|
||||
}
|
||||
|
||||
bool PCHReader::ReadSelectorBlock() {
|
||||
if (Stream.EnterSubBlock(pch::SELECTOR_BLOCK_ID))
|
||||
return Error("Malformed selector block record");
|
||||
|
||||
RecordData Record;
|
||||
while (true) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
switch (Code) {
|
||||
case llvm::bitc::END_BLOCK:
|
||||
if (Stream.ReadBlockEnd())
|
||||
return Error("Error at end of preprocessor block");
|
||||
return false;
|
||||
|
||||
case llvm::bitc::ENTER_SUBBLOCK:
|
||||
// No known subblocks, always skip them.
|
||||
Stream.ReadSubBlockID();
|
||||
if (Stream.SkipBlock())
|
||||
return Error("Malformed block record");
|
||||
continue;
|
||||
|
||||
case llvm::bitc::DEFINE_ABBREV:
|
||||
Stream.ReadAbbrevRecord();
|
||||
continue;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Read a record.
|
||||
Record.clear();
|
||||
pch::PCHRecordTypes RecType =
|
||||
(pch::PCHRecordTypes)Stream.ReadRecord(Code, Record);
|
||||
switch (RecType) {
|
||||
default: // Default behavior: ignore unknown records.
|
||||
break;
|
||||
case pch::SELECTOR_TABLE:
|
||||
unsigned Idx = 1; // Record[0] == pch::SELECTOR_TABLE.
|
||||
unsigned NumSels = Record[Idx++];
|
||||
|
||||
llvm::SmallVector<IdentifierInfo *, 8> KeyIdents;
|
||||
for (unsigned SelIdx = 0; SelIdx < NumSels; SelIdx++) {
|
||||
unsigned NumArgs = Record[Idx++];
|
||||
KeyIdents.clear();
|
||||
if (NumArgs <= 1) {
|
||||
IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
|
||||
assert(II && "DecodeIdentifierInfo returned 0");
|
||||
KeyIdents.push_back(II);
|
||||
} else {
|
||||
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
|
||||
IdentifierInfo *II = DecodeIdentifierInfo(Record[Idx++]);
|
||||
assert(II && "DecodeIdentifierInfo returned 0");
|
||||
KeyIdents.push_back(II);
|
||||
}
|
||||
}
|
||||
Selector Sel = PP.getSelectorTable().getSelector(NumArgs,&KeyIdents[0]);
|
||||
SelectorData.push_back(Sel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PCHReader::PCHReadResult
|
||||
PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
|
||||
PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset,
|
||||
uint64_t &SelectorBlockOffset) {
|
||||
if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) {
|
||||
Error("Malformed block record");
|
||||
return Failure;
|
||||
|
@ -1630,6 +1691,20 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
|
|||
return Failure;
|
||||
}
|
||||
break;
|
||||
|
||||
case pch::SELECTOR_BLOCK_ID:
|
||||
// Skip the selector block for now, but remember where it is. We
|
||||
// want to read it in after the identifier table.
|
||||
if (SelectorBlockOffset) {
|
||||
Error("Multiple selector blocks found.");
|
||||
return Failure;
|
||||
}
|
||||
SelectorBlockOffset = Stream.GetCurrentBitNo();
|
||||
if (Stream.SkipBlock()) {
|
||||
Error("Malformed block record");
|
||||
return Failure;
|
||||
}
|
||||
break;
|
||||
|
||||
case pch::SOURCE_MANAGER_BLOCK_ID:
|
||||
switch (ReadSourceManagerBlock()) {
|
||||
|
@ -1740,7 +1815,6 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
|
|||
TotalLexicalDeclContexts = Record[2];
|
||||
TotalVisibleDeclContexts = Record[3];
|
||||
break;
|
||||
|
||||
case pch::TENTATIVE_DEFINITIONS:
|
||||
if (!TentativeDefinitions.empty()) {
|
||||
Error("Duplicate TENTATIVE_DEFINITIONS record in PCH file");
|
||||
|
@ -1758,7 +1832,6 @@ PCHReader::ReadPCHBlock(uint64_t &PreprocessorBlockOffset) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Error("Premature end of bitstream");
|
||||
return Failure;
|
||||
}
|
||||
|
@ -1791,6 +1864,8 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
|
|||
// We expect a number of well-defined blocks, though we don't necessarily
|
||||
// need to understand them all.
|
||||
uint64_t PreprocessorBlockOffset = 0;
|
||||
uint64_t SelectorBlockOffset = 0;
|
||||
|
||||
while (!Stream.AtEndOfStream()) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
|
||||
|
@ -1810,7 +1885,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
|
|||
}
|
||||
break;
|
||||
case pch::PCH_BLOCK_ID:
|
||||
switch (ReadPCHBlock(PreprocessorBlockOffset)) {
|
||||
switch (ReadPCHBlock(PreprocessorBlockOffset, SelectorBlockOffset)) {
|
||||
case Success:
|
||||
break;
|
||||
|
||||
|
@ -1882,6 +1957,14 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
|
|||
return Failure;
|
||||
}
|
||||
}
|
||||
if (SelectorBlockOffset) {
|
||||
SavedStreamPosition SavedPos(Stream);
|
||||
Stream.JumpToBit(SelectorBlockOffset);
|
||||
if (ReadSelectorBlock()) {
|
||||
Error("Malformed preprocessor block");
|
||||
return Failure;
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
@ -2633,6 +2716,22 @@ IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) {
|
|||
return reinterpret_cast<IdentifierInfo *>(IdentifierData[ID - 1]);
|
||||
}
|
||||
|
||||
Selector PCHReader::DecodeSelector(unsigned ID) {
|
||||
if (ID == 0)
|
||||
return Selector();
|
||||
|
||||
if (SelectorData.empty()) {
|
||||
Error("No selector table in PCH file");
|
||||
return Selector();
|
||||
}
|
||||
|
||||
if (ID > SelectorData.size()) {
|
||||
Error("Selector ID out of range");
|
||||
return Selector();
|
||||
}
|
||||
return SelectorData[ID-1];
|
||||
}
|
||||
|
||||
DeclarationName
|
||||
PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) {
|
||||
DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++];
|
||||
|
|
|
@ -1182,9 +1182,7 @@ void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
|
|||
|
||||
void PCHStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
||||
VisitExpr(E);
|
||||
assert(0 && "Can't write a selector yet!");
|
||||
// FIXME! Write selectors.
|
||||
//Writer.WriteSubStmt(E->getSelector());
|
||||
Writer.AddSelectorRef(E->getSelector(), Record);
|
||||
Writer.AddSourceLocation(E->getAtLoc(), Record);
|
||||
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
||||
Code = pch::EXPR_OBJC_SELECTOR_EXPR;
|
||||
|
@ -1888,6 +1886,26 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) {
|
|||
Stream.EmitRecord(pch::IDENTIFIER_OFFSET, IdentifierOffsets);
|
||||
}
|
||||
|
||||
void PCHWriter::WriteSelectorTable() {
|
||||
Stream.EnterSubblock(pch::SELECTOR_BLOCK_ID, 3);
|
||||
RecordData Record;
|
||||
Record.push_back(pch::SELECTOR_TABLE);
|
||||
Record.push_back(SelectorIDs.size());
|
||||
|
||||
// Create the on-disk representation.
|
||||
for (unsigned selIdx = 0; selIdx < SelVector.size(); selIdx++) {
|
||||
assert(SelVector[selIdx].getAsOpaquePtr() && "NULL Selector found");
|
||||
Record.push_back(SelVector[selIdx].getNumArgs());
|
||||
if (SelVector[selIdx].getNumArgs())
|
||||
for (unsigned i = 0; i < SelVector[selIdx].getNumArgs(); i++)
|
||||
AddIdentifierRef(SelVector[selIdx].getIdentifierInfoForSlot(i), Record);
|
||||
else
|
||||
AddIdentifierRef(SelVector[selIdx].getIdentifierInfoForSlot(0), Record);
|
||||
}
|
||||
Stream.EmitRecord(pch::SELECTOR_TABLE, Record);
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
/// \brief Write a record containing the given attributes.
|
||||
void PCHWriter::WriteAttributeRecord(const Attr *Attr) {
|
||||
RecordData Record;
|
||||
|
@ -2078,6 +2096,7 @@ void PCHWriter::WritePCH(Sema &SemaRef) {
|
|||
WritePreprocessor(PP);
|
||||
WriteTypesBlock(Context);
|
||||
WriteDeclsBlock(Context);
|
||||
WriteSelectorTable();
|
||||
WriteIdentifierTable(PP);
|
||||
Stream.EmitRecord(pch::TYPE_OFFSET, TypeOffsets);
|
||||
Stream.EmitRecord(pch::DECL_OFFSET, DeclOffsets);
|
||||
|
@ -2145,6 +2164,20 @@ pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) {
|
|||
return ID;
|
||||
}
|
||||
|
||||
void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) {
|
||||
if (SelRef.getAsOpaquePtr() == 0) {
|
||||
Record.push_back(0);
|
||||
return;
|
||||
}
|
||||
|
||||
pch::SelectorID &SID = SelectorIDs[SelRef];
|
||||
if (SID == 0) {
|
||||
SID = SelectorIDs.size();
|
||||
SelVector.push_back(SelRef);
|
||||
}
|
||||
Record.push_back(SID);
|
||||
}
|
||||
|
||||
void PCHWriter::AddTypeRef(QualType T, RecordData &Record) {
|
||||
if (T.isNull()) {
|
||||
Record.push_back(pch::PREDEF_TYPE_NULL_ID);
|
||||
|
@ -2223,7 +2256,7 @@ void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) {
|
|||
case DeclarationName::ObjCZeroArgSelector:
|
||||
case DeclarationName::ObjCOneArgSelector:
|
||||
case DeclarationName::ObjCMultiArgSelector:
|
||||
assert(false && "Serialization of Objective-C selectors unavailable");
|
||||
AddSelectorRef(Name.getObjCSelector(), Record);
|
||||
break;
|
||||
|
||||
case DeclarationName::CXXConstructorName:
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
typedef typeof(@"foo" "bar") objc_string;
|
||||
typedef typeof(@encode(int)) objc_encode;
|
||||
typedef typeof(@protocol(foo)) objc_protocol;
|
||||
typedef typeof(@selector(noArgs)) objc_selector_noArgs;
|
||||
typedef typeof(@selector(oneArg:)) objc_selector_oneArg;
|
||||
typedef typeof(@selector(foo:bar:)) objc_selector_twoArg;
|
||||
|
||||
|
||||
// Types.
|
||||
|
|
|
@ -21,3 +21,8 @@ int *T0 = (objc_id_protocol_ty)0; // expected-error {{not a compile-time constan
|
|||
int *T1 = (objc_interface_ty)0; // expected-warning {{aka 'itf *'}}
|
||||
int *T2 = (objc_qual_interface_ty)0; // expected-warning {{aka 'itf<foo> *'}}
|
||||
|
||||
objc_selector_noArgs s1;
|
||||
objc_selector_oneArg s2;
|
||||
objc_selector_twoArg s3;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue