aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/SourceManager.h33
-rw-r--r--include/clang/Lex/Preprocessor.h16
-rw-r--r--lib/Basic/SourceManager.cpp82
-rw-r--r--lib/Lex/LiteralSupport.cpp15
-rw-r--r--lib/Lex/PPExpressions.cpp12
-rw-r--r--lib/Lex/Preprocessor.cpp35
-rw-r--r--test/PCH/changed-files.c11
7 files changed, 150 insertions, 54 deletions
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 5e3cfd2b3c..9657ee4f1a 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -417,7 +417,11 @@ public:
unsigned Offset = 0);
/// \brief Retrieve the memory buffer associated with the given file.
- const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File);
+ ///
+ /// \param Invalid If non-NULL, will be set \c true if an error
+ /// occurs while retrieving the memory buffer.
+ const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File,
+ bool *Invalid = 0);
/// \brief Override the contents of the given source file by providing an
/// already-allocated buffer.
@@ -438,8 +442,9 @@ public:
/// getBuffer - Return the buffer for the specified FileID. If there is an
/// error opening this buffer the first time, this manufactures a temporary
/// buffer and returns a non-empty error string.
- const llvm::MemoryBuffer *getBuffer(FileID FID) const {
- return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Diag);
+ const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const {
+ return getSLocEntry(FID).getFile().getContentCache()->getBuffer(Diag,
+ Invalid);
}
/// getFileEntryForID - Returns the FileEntry record for the provided FileID.
@@ -571,31 +576,37 @@ public:
/// getCharacterData - Return a pointer to the start of the specified location
/// in the appropriate spelling MemoryBuffer.
- const char *getCharacterData(SourceLocation SL) const;
+ ///
+ /// \param Invalid If non-NULL, will be set \c true if an error occurs.
+ const char *getCharacterData(SourceLocation SL, bool *Invalid = 0) const;
/// getColumnNumber - Return the column # for the specified file position.
/// This is significantly cheaper to compute than the line number. This
/// returns zero if the column number isn't known. This may only be called on
/// a file sloc, so you must choose a spelling or instantiation location
/// before calling this method.
- unsigned getColumnNumber(FileID FID, unsigned FilePos) const;
- unsigned getSpellingColumnNumber(SourceLocation Loc) const;
- unsigned getInstantiationColumnNumber(SourceLocation Loc) const;
+ unsigned getColumnNumber(FileID FID, unsigned FilePos,
+ bool *Invalid = 0) const;
+ unsigned getSpellingColumnNumber(SourceLocation Loc,
+ bool *Invalid = 0) const;
+ unsigned getInstantiationColumnNumber(SourceLocation Loc,
+ bool *Invalid = 0) const;
/// getLineNumber - Given a SourceLocation, return the spelling line number
/// for the position indicated. This requires building and caching a table of
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
/// about to emit a diagnostic.
- unsigned getLineNumber(FileID FID, unsigned FilePos) const;
+ unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = 0) const;
- unsigned getInstantiationLineNumber(SourceLocation Loc) const;
- unsigned getSpellingLineNumber(SourceLocation Loc) const;
+ unsigned getInstantiationLineNumber(SourceLocation Loc,
+ bool *Invalid = 0) const;
+ unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = 0) const;
/// Return the filename or buffer identifier of the buffer the location is in.
/// Note that this name does not respect #line directives. Use getPresumedLoc
/// for normal clients.
- const char *getBufferName(SourceLocation Loc) const;
+ const char *getBufferName(SourceLocation Loc, bool *Invalid = 0) const;
/// getFileCharacteristic - return the file characteristic of the specified
/// source location, indicating whether this is a normal file, a system
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index e29ece1da6..2b27a06070 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -547,7 +547,9 @@ public:
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
- std::string getSpelling(const Token &Tok) const;
+ ///
+ /// \param Invalid If non-NULL, will be set \c true if an error occurs.
+ std::string getSpelling(const Token &Tok, bool *Invalid = 0) const;
/// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a
/// token is the characters used to represent the token in the source file
@@ -556,7 +558,8 @@ public:
/// UCNs, etc.
static std::string getSpelling(const Token &Tok,
const SourceManager &SourceMgr,
- const LangOptions &Features);
+ const LangOptions &Features,
+ bool *Invalid = 0);
/// getSpelling - This method is used to get the spelling of a token into a
/// preallocated buffer, instead of as an std::string. The caller is required
@@ -568,17 +571,20 @@ public:
/// to point to a constant buffer with the data already in it (avoiding a
/// copy). The caller is not allowed to modify the returned buffer pointer
/// if an internal buffer is returned.
- unsigned getSpelling(const Token &Tok, const char *&Buffer) const;
+ unsigned getSpelling(const Token &Tok, const char *&Buffer,
+ bool *Invalid = 0) const;
/// getSpelling - This method is used to get the spelling of a token into a
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
llvm::StringRef getSpelling(const Token &Tok,
- llvm::SmallVectorImpl<char> &Buffer) const;
+ llvm::SmallVectorImpl<char> &Buffer,
+ bool *Invalid = 0) const;
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
/// with length 1, return the character.
- char getSpellingOfSingleCharacterNumericConstant(const Token &Tok) const {
+ char getSpellingOfSingleCharacterNumericConstant(const Token &Tok,
+ bool *Invalid = 0) const {
assert(Tok.is(tok::numeric_constant) &&
Tok.getLength() == 1 && "Called on unsupported token");
assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1");
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index f0a0d4c1bb..6335504a7d 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -457,10 +457,11 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc,
}
const llvm::MemoryBuffer *
-SourceManager::getMemoryBufferForFile(const FileEntry *File) {
+SourceManager::getMemoryBufferForFile(const FileEntry *File,
+ bool *Invalid) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
assert(IR && "getOrCreateContentCache() cannot return NULL");
- return IR->getBuffer(Diag);
+ return IR->getBuffer(Diag, Invalid);
}
bool SourceManager::overrideFileContents(const FileEntry *SourceFile,
@@ -701,21 +702,34 @@ SourceManager::getInstantiationRange(SourceLocation Loc) const {
/// getCharacterData - Return a pointer to the start of the specified location
/// in the appropriate MemoryBuffer.
-const char *SourceManager::getCharacterData(SourceLocation SL) const {
+const char *SourceManager::getCharacterData(SourceLocation SL,
+ bool *Invalid) const {
// Note that this is a hot function in the getSpelling() path, which is
// heavily used by -E mode.
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL);
// Note that calling 'getBuffer()' may lazily page in a source file.
- return getSLocEntry(LocInfo.first).getFile().getContentCache()
- ->getBuffer(Diag)->getBufferStart() + LocInfo.second;
+ bool CharDataInvalid = false;
+ const llvm::MemoryBuffer *Buffer
+ = getSLocEntry(LocInfo.first).getFile().getContentCache()->getBuffer(Diag,
+ &CharDataInvalid);
+ if (Invalid)
+ *Invalid = CharDataInvalid;
+ return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
}
/// getColumnNumber - Return the column # for the specified file position.
/// this is significantly cheaper to compute than the line number.
-unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const {
- const char *Buf = getBuffer(FID)->getBufferStart();
+unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
+ bool *Invalid) const {
+ bool MyInvalid = false;
+ const char *Buf = getBuffer(FID, &MyInvalid)->getBufferStart();
+ if (Invalid)
+ *Invalid = MyInvalid;
+
+ if (MyInvalid)
+ return 1;
unsigned LineStart = FilePos;
while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r')
@@ -723,27 +737,30 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos) const {
return FilePos-LineStart+1;
}
-unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc) const {
+unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
- return getColumnNumber(LocInfo.first, LocInfo.second);
+ return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const {
+unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
- return getColumnNumber(LocInfo.first, LocInfo.second);
+ return getColumnNumber(LocInfo.first, LocInfo.second, Invalid);
}
-
-
static DISABLE_INLINE void ComputeLineNumbers(Diagnostic &Diag,
ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc);
+ llvm::BumpPtrAllocator &Alloc,
+ bool &Invalid);
static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc){
+ llvm::BumpPtrAllocator &Alloc, bool &Invalid) {
// Note that calling 'getBuffer()' may lazily page in the file.
- const MemoryBuffer *Buffer = FI->getBuffer(Diag);
+ const MemoryBuffer *Buffer = FI->getBuffer(Diag, &Invalid);
+ if (Invalid)
+ return;
// Find the file offsets of all of the *physical* source lines. This does
// not look at trigraphs, escaped newlines, or anything else tricky.
@@ -789,7 +806,8 @@ static void ComputeLineNumbers(Diagnostic &Diag, ContentCache* FI,
/// for the position indicated. This requires building and caching a table of
/// line offsets for the MemoryBuffer, so this is not cheap: use only when
/// about to emit a diagnostic.
-unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
+unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos,
+ bool *Invalid) const {
ContentCache *Content;
if (LastLineNoFileIDQuery == FID)
Content = LastLineNoContentCache;
@@ -799,8 +817,15 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
- if (Content->SourceLineCache == 0)
- ComputeLineNumbers(Diag, Content, ContentCacheAlloc);
+ if (Content->SourceLineCache == 0) {
+ bool MyInvalid = false;
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ if (Invalid)
+ *Invalid = MyInvalid;
+ if (MyInvalid)
+ return 1;
+ } else if (Invalid)
+ *Invalid = false;
// Okay, we know we have a line number table. Do a binary search to find the
// line number that this character position lands on.
@@ -886,12 +911,14 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos) const {
return LineNo;
}
-unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc) const {
+unsigned SourceManager::getInstantiationLineNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
}
-unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc) const {
+unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return 0;
std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc);
return getLineNumber(LocInfo.first, LocInfo.second);
@@ -931,10 +958,11 @@ SourceManager::getFileCharacteristic(SourceLocation Loc) const {
/// Return the filename or buffer identifier of the buffer the location is in.
/// Note that this name does not respect #line directives. Use getPresumedLoc
/// for normal clients.
-const char *SourceManager::getBufferName(SourceLocation Loc) const {
+const char *SourceManager::getBufferName(SourceLocation Loc,
+ bool *Invalid) const {
if (Loc.isInvalid()) return "<invalid loc>";
- return getBuffer(getFileID(Loc))->getBufferIdentifier();
+ return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier();
}
@@ -1014,8 +1042,12 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,
// If this is the first use of line information for this buffer, compute the
/// SourceLineCache for it on demand.
- if (Content->SourceLineCache == 0)
- ComputeLineNumbers(Diag, Content, ContentCacheAlloc);
+ if (Content->SourceLineCache == 0) {
+ bool MyInvalid = false;
+ ComputeLineNumbers(Diag, Content, ContentCacheAlloc, MyInvalid);
+ if (MyInvalid)
+ return SourceLocation();
+ }
// Find the first file ID that corresponds to the given file.
FileID FirstFID;
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 004e6755e5..1cfa0e3745 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -806,7 +806,14 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks,
// Get the spelling of the token, which eliminates trigraphs, etc. We know
// that ThisTokBuf points to a buffer that is big enough for the whole token
// and 'spelled' tokens can only shrink.
- unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf);
+ bool StringInvalid = false;
+ unsigned ThisTokLen = PP.getSpelling(StringToks[i], ThisTokBuf,
+ &StringInvalid);
+ if (StringInvalid) {
+ hadError = 1;
+ continue;
+ }
+
const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote.
// TODO: Input character set mapping support.
@@ -904,8 +911,12 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok,
llvm::SmallString<16> SpellingBuffer;
SpellingBuffer.resize(Tok.getLength());
+ bool StringInvalid = false;
const char *SpellingPtr = &SpellingBuffer[0];
- unsigned TokLen = PP.getSpelling(Tok, SpellingPtr);
+ unsigned TokLen = PP.getSpelling(Tok, SpellingPtr, &StringInvalid);
+ if (StringInvalid) {
+ return 0;
+ }
assert(SpellingPtr[0] != 'L' && "Doesn't handle wide strings yet");
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index ede129edcb..756ce27a93 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -170,7 +170,12 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
return true;
case tok::numeric_constant: {
llvm::SmallString<64> IntegerBuffer;
- llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer);
+ bool NumberInvalid = false;
+ llvm::StringRef Spelling = PP.getSpelling(PeekTok, IntegerBuffer,
+ &NumberInvalid);
+ if (NumberInvalid)
+ return true; // a diagnostic was already reported
+
NumericLiteralParser Literal(Spelling.begin(), Spelling.end(),
PeekTok.getLocation(), PP);
if (Literal.hadError)
@@ -216,7 +221,10 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
}
case tok::char_constant: { // 'x'
llvm::SmallString<32> CharBuffer;
- llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer);
+ bool CharInvalid = false;
+ llvm::StringRef ThisTok = PP.getSpelling(PeekTok, CharBuffer, &CharInvalid);
+ if (CharInvalid)
+ return true;
CharLiteralParser Literal(ThisTok.begin(), ThisTok.end(),
PeekTok.getLocation(), PP);
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index a6efe7f5bc..5584b18da1 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -282,11 +282,19 @@ bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const {
/// UCNs, etc.
std::string Preprocessor::getSpelling(const Token &Tok,
const SourceManager &SourceMgr,
- const LangOptions &Features) {
+ const LangOptions &Features,
+ bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
// If this token contains nothing interesting, return it directly.
- const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation());
+ bool CharDataInvalid = false;
+ const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
+ &CharDataInvalid);
+ if (Invalid)
+ *Invalid = CharDataInvalid;
+ if (CharDataInvalid)
+ return std::string();
+
if (!Tok.needsCleaning())
return std::string(TokStart, TokStart+Tok.getLength());
@@ -310,8 +318,8 @@ std::string Preprocessor::getSpelling(const Token &Tok,
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
-std::string Preprocessor::getSpelling(const Token &Tok) const {
- return getSpelling(Tok, SourceMgr, Features);
+std::string Preprocessor::getSpelling(const Token &Tok, bool *Invalid) const {
+ return getSpelling(Tok, SourceMgr, Features, Invalid);
}
/// getSpelling - This method is used to get the spelling of a token into a
@@ -325,7 +333,7 @@ std::string Preprocessor::getSpelling(const Token &Tok) const {
/// copy). The caller is not allowed to modify the returned buffer pointer
/// if an internal buffer is returned.
unsigned Preprocessor::getSpelling(const Token &Tok,
- const char *&Buffer) const {
+ const char *&Buffer, bool *Invalid) const {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
// If this token is an identifier, just return the string from the identifier
@@ -341,8 +349,16 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
if (Tok.isLiteral())
TokStart = Tok.getLiteralData();
- if (TokStart == 0)
- TokStart = SourceMgr.getCharacterData(Tok.getLocation());
+ if (TokStart == 0) {
+ bool CharDataInvalid = false;
+ TokStart = SourceMgr.getCharacterData(Tok.getLocation(), &CharDataInvalid);
+ if (Invalid)
+ *Invalid = CharDataInvalid;
+ if (CharDataInvalid) {
+ Buffer = "";
+ return 0;
+ }
+ }
// If this token contains nothing interesting, return it directly.
if (!Tok.needsCleaning()) {
@@ -368,7 +384,8 @@ unsigned Preprocessor::getSpelling(const Token &Tok,
/// SmallVector. Note that the returned StringRef may not point to the
/// supplied buffer if a copy can be avoided.
llvm::StringRef Preprocessor::getSpelling(const Token &Tok,
- llvm::SmallVectorImpl<char> &Buffer) const {
+ llvm::SmallVectorImpl<char> &Buffer,
+ bool *Invalid) const {
// Try the fast path.
if (const IdentifierInfo *II = Tok.getIdentifierInfo())
return II->getName();
@@ -378,7 +395,7 @@ llvm::StringRef Preprocessor::getSpelling(const Token &Tok,
Buffer.resize(Tok.getLength());
const char *Ptr = Buffer.data();
- unsigned Len = getSpelling(Tok, Ptr);
+ unsigned Len = getSpelling(Tok, Ptr, Invalid);
return llvm::StringRef(Ptr, Len);
}
diff --git a/test/PCH/changed-files.c b/test/PCH/changed-files.c
new file mode 100644
index 0000000000..36453c48e7
--- /dev/null
+++ b/test/PCH/changed-files.c
@@ -0,0 +1,11 @@
+const char *s0 = m0;
+
+// RUN: echo '#define m0 ""' > %t.h
+// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUN: echo '' > %t.h
+// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2>&1 | grep "size of file"
+
+// RUN: echo '#define m0 000' > %t.h
+// RUN: %clang_cc1 -emit-pch -o %t.h.pch %t.h
+// RUN: echo '' > %t.h
+// RUN: not %clang_cc1 -include-pch %t.h.pch %s 2>&1 | grep "size of file"