зеркало из https://github.com/microsoft/clang.git
Add PCH support for #import.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69987 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
ff11cd148b
Коммит
83d63c7881
|
@ -211,7 +211,11 @@ namespace clang {
|
|||
|
||||
/// \brief The value of the next __COUNTER__ to dispense.
|
||||
/// [PP_COUNTER_VALUE, Val]
|
||||
PP_COUNTER_VALUE = 4
|
||||
PP_COUNTER_VALUE = 4,
|
||||
|
||||
/// \brief Describes one header file info [isImport, DirInfo, NumIncludes]
|
||||
/// ControlloingMacro is optional.
|
||||
PP_HEADER_FILE_INFO = 5
|
||||
};
|
||||
|
||||
/// \defgroup PCHAST Precompiled header AST constants
|
||||
|
|
|
@ -23,6 +23,30 @@ class FileEntry;
|
|||
class FileManager;
|
||||
class IdentifierInfo;
|
||||
|
||||
/// HeaderFileInfo - The preprocessor keeps track of this information for each
|
||||
/// file that is #included.
|
||||
struct HeaderFileInfo {
|
||||
/// isImport - True if this is a #import'd or #pragma once file.
|
||||
bool isImport : 1;
|
||||
|
||||
/// DirInfo - Keep track of whether this is a system header, and if so,
|
||||
/// whether it is C++ clean or not. This can be set by the include paths or
|
||||
/// by #pragma gcc system_header. This is an instance of
|
||||
/// SrcMgr::CharacteristicKind.
|
||||
unsigned DirInfo : 2;
|
||||
|
||||
/// NumIncludes - This is the number of times the file has been included
|
||||
/// already.
|
||||
unsigned short NumIncludes;
|
||||
|
||||
/// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard
|
||||
/// that protects the entire contents of the file, this is the identifier
|
||||
/// for the macro that controls whether or not it has any effect.
|
||||
const IdentifierInfo *ControllingMacro;
|
||||
|
||||
HeaderFileInfo() : isImport(false), DirInfo(SrcMgr::C_User),
|
||||
NumIncludes(0), ControllingMacro(0) {}
|
||||
};
|
||||
|
||||
/// HeaderSearch - This class encapsulates the information needed to find the
|
||||
/// file referenced by a #include or #include_next, (sub-)framework lookup, etc.
|
||||
|
@ -39,35 +63,10 @@ class HeaderSearch {
|
|||
unsigned SystemDirIdx;
|
||||
bool NoCurDirSearch;
|
||||
|
||||
/// PreFileInfo - The preprocessor keeps track of this information for each
|
||||
/// file that is #included.
|
||||
struct PerFileInfo {
|
||||
/// isImport - True if this is a #import'd or #pragma once file.
|
||||
bool isImport : 1;
|
||||
|
||||
/// DirInfo - Keep track of whether this is a system header, and if so,
|
||||
/// whether it is C++ clean or not. This can be set by the include paths or
|
||||
/// by #pragma gcc system_header. This is an instance of
|
||||
/// SrcMgr::CharacteristicKind.
|
||||
unsigned DirInfo : 2;
|
||||
|
||||
/// NumIncludes - This is the number of times the file has been included
|
||||
/// already.
|
||||
unsigned short NumIncludes;
|
||||
|
||||
/// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard
|
||||
/// that protects the entire contents of the file, this is the identifier
|
||||
/// for the macro that controls whether or not it has any effect.
|
||||
const IdentifierInfo *ControllingMacro;
|
||||
|
||||
PerFileInfo() : isImport(false), DirInfo(SrcMgr::C_User),
|
||||
NumIncludes(0), ControllingMacro(0) {}
|
||||
};
|
||||
|
||||
/// FileInfo - This contains all of the preprocessor-specific data about files
|
||||
/// that are included. The vector is indexed by the FileEntry's UID.
|
||||
///
|
||||
std::vector<PerFileInfo> FileInfo;
|
||||
std::vector<HeaderFileInfo> FileInfo;
|
||||
|
||||
/// LookupFileCache - This is keeps track of each lookup performed by
|
||||
/// LookupFile. The first part of the value is the starting index in
|
||||
|
@ -191,12 +190,19 @@ public:
|
|||
|
||||
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
|
||||
|
||||
typedef std::vector<HeaderFileInfo>::iterator header_file_iterator;
|
||||
header_file_iterator header_file_begin() { return FileInfo.begin(); }
|
||||
header_file_iterator header_file_end() { return FileInfo.end(); }
|
||||
|
||||
// Used by PCHReader.
|
||||
void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID);
|
||||
|
||||
void PrintStats();
|
||||
private:
|
||||
|
||||
/// getFileInfo - Return the PerFileInfo structure for the specified
|
||||
/// getFileInfo - Return the HeaderFileInfo structure for the specified
|
||||
/// FileEntry.
|
||||
PerFileInfo &getFileInfo(const FileEntry *FE);
|
||||
HeaderFileInfo &getFileInfo(const FileEntry *FE);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "clang/AST/Type.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Basic/OnDiskHashTable.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/SourceManagerInternals.h"
|
||||
|
@ -1444,6 +1445,7 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
|
|||
RecordData Record;
|
||||
llvm::SmallVector<IdentifierInfo*, 16> MacroArgs;
|
||||
MacroInfo *Macro = 0;
|
||||
|
||||
while (true) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
switch (Code) {
|
||||
|
@ -1536,7 +1538,9 @@ void PCHReader::ReadMacroRecord(uint64_t Offset) {
|
|||
Macro->AddTokenToBody(Tok);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case pch::PP_HEADER_FILE_INFO:
|
||||
break; // Already processed by ReadPreprocessorBlock().
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1545,6 +1549,7 @@ bool PCHReader::ReadPreprocessorBlock() {
|
|||
return Error("Malformed preprocessor block record");
|
||||
|
||||
RecordData Record;
|
||||
unsigned NumHeaderInfos = 0;
|
||||
while (true) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
switch (Code) {
|
||||
|
@ -1581,8 +1586,16 @@ bool PCHReader::ReadPreprocessorBlock() {
|
|||
case pch::PP_MACRO_OBJECT_LIKE:
|
||||
case pch::PP_MACRO_FUNCTION_LIKE:
|
||||
case pch::PP_TOKEN:
|
||||
// Once we've hit a macro definition or a token, we're done.
|
||||
return false;
|
||||
break;
|
||||
case pch::PP_HEADER_FILE_INFO: {
|
||||
HeaderFileInfo HFI;
|
||||
HFI.isImport = Record[0];
|
||||
HFI.DirInfo = Record[1];
|
||||
HFI.NumIncludes = Record[2];
|
||||
HFI.ControllingMacro = DecodeIdentifierInfo(Record[3]);
|
||||
PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, NumHeaderInfos++);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "clang/AST/Type.h"
|
||||
#include "clang/Lex/MacroInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/OnDiskHashTable.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
|
@ -1548,6 +1549,21 @@ void PCHWriter::WritePreprocessor(const Preprocessor &PP) {
|
|||
++NumMacros;
|
||||
}
|
||||
|
||||
// Loop over all the header files.
|
||||
HeaderSearch &HS = PP.getHeaderSearchInfo();
|
||||
for (HeaderSearch::header_file_iterator I = HS.header_file_begin(),
|
||||
E = HS.header_file_end();
|
||||
I != E; ++I) {
|
||||
Record.push_back((*I).isImport);
|
||||
Record.push_back((*I).DirInfo);
|
||||
Record.push_back((*I).NumIncludes);
|
||||
if ((*I).ControllingMacro)
|
||||
AddIdentifierRef((*I).ControllingMacro, Record);
|
||||
else
|
||||
Record.push_back(0);
|
||||
Stream.EmitRecord(pch::PP_HEADER_FILE_INFO, Record);
|
||||
Record.clear();
|
||||
}
|
||||
Stream.ExitBlock();
|
||||
}
|
||||
|
||||
|
|
|
@ -377,14 +377,20 @@ LookupSubframeworkHeader(const char *FilenameStart,
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
/// getFileInfo - Return the PerFileInfo structure for the specified
|
||||
/// getFileInfo - Return the HeaderFileInfo structure for the specified
|
||||
/// FileEntry.
|
||||
HeaderSearch::PerFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
|
||||
HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
|
||||
if (FE->getUID() >= FileInfo.size())
|
||||
FileInfo.resize(FE->getUID()+1);
|
||||
return FileInfo[FE->getUID()];
|
||||
}
|
||||
|
||||
void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
|
||||
if (UID >= FileInfo.size())
|
||||
FileInfo.resize(UID+1);
|
||||
FileInfo[UID] = HFI;
|
||||
}
|
||||
|
||||
/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
|
||||
/// #include, #include_next, or #import directive. Return false if #including
|
||||
/// the file will have no effect or true if we should include it.
|
||||
|
@ -392,7 +398,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(const FileEntry *File, bool isImport){
|
|||
++NumIncluded; // Count # of attempted #includes.
|
||||
|
||||
// Get information about this file.
|
||||
PerFileInfo &FileInfo = getFileInfo(File);
|
||||
HeaderFileInfo &FileInfo = getFileInfo(File);
|
||||
|
||||
// If this is a #import directive, check that we have not already imported
|
||||
// this header.
|
||||
|
|
|
@ -179,7 +179,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
|
|||
if (CurPPLexer) { // Not ending a macro, ignore it.
|
||||
if (const IdentifierInfo *ControllingMacro =
|
||||
CurPPLexer->MIOpt.GetControllingMacroAtEndOfFile()) {
|
||||
// Okay, this has a controlling macro, remember in PerFileInfo.
|
||||
// Okay, this has a controlling macro, remember in HeaderFileInfo.
|
||||
if (const FileEntry *FE =
|
||||
SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))
|
||||
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
/* For use with the objc_import.m test */
|
||||
|
||||
@interface TestPCH
|
||||
+ alloc;
|
||||
- (void)instMethod;
|
||||
@end
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// Test this without pch.
|
||||
// RUN: clang-cc -include %S/objc_import.h -fsyntax-only -verify %s &&
|
||||
|
||||
// Test with pch.
|
||||
// RUN: clang-cc -x=objective-c -emit-pch -o %t %S/objc_import.h &&
|
||||
// RUN: clang-cc -include-pch %t -fsyntax-only -verify %s
|
||||
|
||||
#import "objc_import.h"
|
||||
|
||||
void func() {
|
||||
TestPCH *xx;
|
||||
|
||||
xx = [TestPCH alloc];
|
||||
[xx instMethod];
|
||||
}
|
Загрузка…
Ссылка в новой задаче