forked from OSchip/llvm-project
Give files from #line the characteristics of the current file
This allows #line directives to appear in system headers that have code that clang would normally warn on. This is compatible with GCC, which is easy to test by running `gcc -E`. Fixes PR30752 llvm-svn: 303582
This commit is contained in:
parent
b238cb8fbc
commit
eb00ee07be
|
@ -1399,10 +1399,9 @@ public:
|
|||
/// specified by Loc.
|
||||
///
|
||||
/// If FilenameID is -1, it is considered to be unspecified.
|
||||
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID);
|
||||
void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID,
|
||||
bool IsFileEntry, bool IsFileExit,
|
||||
bool IsSystemHeader, bool IsExternCHeader);
|
||||
SrcMgr::CharacteristicKind FileKind);
|
||||
|
||||
/// \brief Determine if the source manager has a line table.
|
||||
bool hasLineTable() const { return LineTable != nullptr; }
|
||||
|
|
|
@ -101,8 +101,6 @@ public:
|
|||
}
|
||||
unsigned getNumFilenames() const { return FilenamesByID.size(); }
|
||||
|
||||
void AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID);
|
||||
void AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID,
|
||||
unsigned EntryExit, SrcMgr::CharacteristicKind FileKind);
|
||||
|
|
|
@ -183,48 +183,22 @@ unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) {
|
|||
return IterBool.first->second;
|
||||
}
|
||||
|
||||
/// AddLineNote - Add a line note to the line table that indicates that there
|
||||
/// is a \#line at the specified FID/Offset location which changes the presumed
|
||||
/// location to LineNo/FilenameID.
|
||||
void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID) {
|
||||
std::vector<LineEntry> &Entries = LineEntries[FID];
|
||||
|
||||
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
|
||||
"Adding line entries out of order!");
|
||||
|
||||
SrcMgr::CharacteristicKind Kind = SrcMgr::C_User;
|
||||
unsigned IncludeOffset = 0;
|
||||
|
||||
if (!Entries.empty()) {
|
||||
// If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember
|
||||
// that we are still in "foo.h".
|
||||
if (FilenameID == -1)
|
||||
FilenameID = Entries.back().FilenameID;
|
||||
|
||||
// If we are after a line marker that switched us to system header mode, or
|
||||
// that set #include information, preserve it.
|
||||
Kind = Entries.back().FileKind;
|
||||
IncludeOffset = Entries.back().IncludeOffset;
|
||||
}
|
||||
|
||||
Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind,
|
||||
IncludeOffset));
|
||||
}
|
||||
|
||||
/// AddLineNote This is the same as the previous version of AddLineNote, but is
|
||||
/// used for GNU line markers. If EntryExit is 0, then this doesn't change the
|
||||
/// presumed \#include stack. If it is 1, this is a file entry, if it is 2 then
|
||||
/// this is a file exit. FileKind specifies whether this is a system header or
|
||||
/// extern C system header.
|
||||
void LineTableInfo::AddLineNote(FileID FID, unsigned Offset,
|
||||
unsigned LineNo, int FilenameID,
|
||||
unsigned EntryExit,
|
||||
/// Add a line note to the line table that indicates that there is a \#line or
|
||||
/// GNU line marker at the specified FID/Offset location which changes the
|
||||
/// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't
|
||||
/// change the presumed \#include stack. If it is 1, this is a file entry, if
|
||||
/// it is 2 then this is a file exit. FileKind specifies whether this is a
|
||||
/// system header or extern C system header.
|
||||
void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo,
|
||||
int FilenameID, unsigned EntryExit,
|
||||
SrcMgr::CharacteristicKind FileKind) {
|
||||
assert(FilenameID != -1 && "Unspecified filename should use other accessor");
|
||||
|
||||
std::vector<LineEntry> &Entries = LineEntries[FID];
|
||||
|
||||
// An unspecified FilenameID means use the last filename if available, or the
|
||||
// main source file otherwise.
|
||||
if (FilenameID == -1 && !Entries.empty())
|
||||
FilenameID = Entries.back().FilenameID;
|
||||
|
||||
assert((Entries.empty() || Entries.back().FileOffset < Offset) &&
|
||||
"Adding line entries out of order!");
|
||||
|
||||
|
@ -281,47 +255,20 @@ unsigned SourceManager::getLineTableFilenameID(StringRef Name) {
|
|||
return getLineTable().getLineTableFilenameID(Name);
|
||||
}
|
||||
|
||||
|
||||
/// AddLineNote - Add a line note to the line table for the FileID and offset
|
||||
/// specified by Loc. If FilenameID is -1, it is considered to be
|
||||
/// unspecified.
|
||||
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
||||
int FilenameID) {
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
|
||||
|
||||
bool Invalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (!Entry.isFile() || Invalid)
|
||||
return;
|
||||
|
||||
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
|
||||
|
||||
// Remember that this file has #line directives now if it doesn't already.
|
||||
const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives();
|
||||
|
||||
getLineTable().AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID);
|
||||
}
|
||||
|
||||
/// AddLineNote - Add a GNU line marker to the line table.
|
||||
void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
||||
int FilenameID, bool IsFileEntry,
|
||||
bool IsFileExit, bool IsSystemHeader,
|
||||
bool IsExternCHeader) {
|
||||
// If there is no filename and no flags, this is treated just like a #line,
|
||||
// which does not change the flags of the previous line marker.
|
||||
if (FilenameID == -1) {
|
||||
assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader &&
|
||||
"Can't set flags without setting the filename!");
|
||||
return AddLineNote(Loc, LineNo, FilenameID);
|
||||
}
|
||||
|
||||
bool IsFileExit,
|
||||
SrcMgr::CharacteristicKind FileKind) {
|
||||
std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc);
|
||||
|
||||
bool Invalid = false;
|
||||
const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid);
|
||||
if (!Entry.isFile() || Invalid)
|
||||
return;
|
||||
|
||||
|
||||
const SrcMgr::FileInfo &FileInfo = Entry.getFile();
|
||||
|
||||
// Remember that this file has #line directives now if it doesn't already.
|
||||
|
@ -329,14 +276,6 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo,
|
|||
|
||||
(void) getLineTable();
|
||||
|
||||
SrcMgr::CharacteristicKind FileKind;
|
||||
if (IsExternCHeader)
|
||||
FileKind = SrcMgr::C_ExternCSystem;
|
||||
else if (IsSystemHeader)
|
||||
FileKind = SrcMgr::C_System;
|
||||
else
|
||||
FileKind = SrcMgr::C_User;
|
||||
|
||||
unsigned EntryExit = 0;
|
||||
if (IsFileEntry)
|
||||
EntryExit = 1;
|
||||
|
|
|
@ -252,7 +252,8 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI,
|
|||
|
||||
if (AddLineNote)
|
||||
CI.getSourceManager().AddLineNote(
|
||||
LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile));
|
||||
LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false,
|
||||
false, SrcMgr::C_User);
|
||||
|
||||
return T.getLocation();
|
||||
}
|
||||
|
|
|
@ -1171,18 +1171,26 @@ void Preprocessor::HandleLineDirective() {
|
|||
CheckEndOfDirective("line", true);
|
||||
}
|
||||
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID);
|
||||
// Take the file kind of the file containing the #line directive. #line
|
||||
// directives are often used for generated sources from the same codebase, so
|
||||
// the new file should generally be classified the same way as the current
|
||||
// file. This is visible in GCC's pre-processed output, which rewrites #line
|
||||
// to GNU line markers.
|
||||
SrcMgr::CharacteristicKind FileKind =
|
||||
SourceMgr.getFileCharacteristic(DigitTok.getLocation());
|
||||
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, false,
|
||||
false, FileKind);
|
||||
|
||||
if (Callbacks)
|
||||
Callbacks->FileChanged(CurPPLexer->getSourceLocation(),
|
||||
PPCallbacks::RenameFile,
|
||||
SrcMgr::C_User);
|
||||
PPCallbacks::RenameFile, FileKind);
|
||||
}
|
||||
|
||||
/// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line
|
||||
/// marker directive.
|
||||
static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
|
||||
bool &IsSystemHeader, bool &IsExternCHeader,
|
||||
SrcMgr::CharacteristicKind &FileKind,
|
||||
Preprocessor &PP) {
|
||||
unsigned FlagVal;
|
||||
Token FlagTok;
|
||||
|
@ -1233,7 +1241,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
|
|||
return true;
|
||||
}
|
||||
|
||||
IsSystemHeader = true;
|
||||
FileKind = SrcMgr::C_System;
|
||||
|
||||
PP.Lex(FlagTok);
|
||||
if (FlagTok.is(tok::eod)) return false;
|
||||
|
@ -1247,7 +1255,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit,
|
|||
return true;
|
||||
}
|
||||
|
||||
IsExternCHeader = true;
|
||||
FileKind = SrcMgr::C_ExternCSystem;
|
||||
|
||||
PP.Lex(FlagTok);
|
||||
if (FlagTok.is(tok::eod)) return false;
|
||||
|
@ -1277,14 +1285,15 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
|
|||
Lex(StrTok);
|
||||
|
||||
bool IsFileEntry = false, IsFileExit = false;
|
||||
bool IsSystemHeader = false, IsExternCHeader = false;
|
||||
int FilenameID = -1;
|
||||
SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
|
||||
|
||||
// If the StrTok is "eod", then it wasn't present. Otherwise, it must be a
|
||||
// string followed by eod.
|
||||
if (StrTok.is(tok::eod))
|
||||
; // ok
|
||||
else if (StrTok.isNot(tok::string_literal)) {
|
||||
if (StrTok.is(tok::eod)) {
|
||||
// Treat this like "#line NN", which doesn't change file characteristics.
|
||||
FileKind = SourceMgr.getFileCharacteristic(DigitTok.getLocation());
|
||||
} else if (StrTok.isNot(tok::string_literal)) {
|
||||
Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
|
||||
return DiscardUntilEndOfDirective();
|
||||
} else if (StrTok.hasUDSuffix()) {
|
||||
|
@ -1303,15 +1312,13 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
|
|||
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
|
||||
|
||||
// If a filename was present, read any flags that are present.
|
||||
if (ReadLineMarkerFlags(IsFileEntry, IsFileExit,
|
||||
IsSystemHeader, IsExternCHeader, *this))
|
||||
if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this))
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a line note with this information.
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID,
|
||||
IsFileEntry, IsFileExit,
|
||||
IsSystemHeader, IsExternCHeader);
|
||||
SourceMgr.AddLineNote(DigitTok.getLocation(), LineNo, FilenameID, IsFileEntry,
|
||||
IsFileExit, FileKind);
|
||||
|
||||
// If the preprocessor has callbacks installed, notify them of the #line
|
||||
// change. This is used so that the line marker comes out in -E mode for
|
||||
|
@ -1322,11 +1329,6 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
|
|||
Reason = PPCallbacks::EnterFile;
|
||||
else if (IsFileExit)
|
||||
Reason = PPCallbacks::ExitFile;
|
||||
SrcMgr::CharacteristicKind FileKind = SrcMgr::C_User;
|
||||
if (IsExternCHeader)
|
||||
FileKind = SrcMgr::C_ExternCSystem;
|
||||
else if (IsSystemHeader)
|
||||
FileKind = SrcMgr::C_System;
|
||||
|
||||
Callbacks->FileChanged(CurPPLexer->getSourceLocation(), Reason, FileKind);
|
||||
}
|
||||
|
|
|
@ -475,9 +475,9 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
|
|||
// Emit a line marker. This will change any source locations from this point
|
||||
// forward to realize they are in a system header.
|
||||
// Create a line note with this information.
|
||||
SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine()+1,
|
||||
SourceMgr.AddLineNote(SysHeaderTok.getLocation(), PLoc.getLine() + 1,
|
||||
FilenameID, /*IsEntry=*/false, /*IsExit=*/false,
|
||||
/*IsSystem=*/true, /*IsExternC=*/false);
|
||||
SrcMgr::C_System);
|
||||
}
|
||||
|
||||
/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#line 1 "foo.h"
|
||||
foo();
|
|
@ -0,0 +1 @@
|
|||
foo();
|
|
@ -0,0 +1,20 @@
|
|||
// RUN: %clang_cc1 -Wall %s -isystem %S/Inputs/SystemHeaderPrefix -verify
|
||||
// RUN: %clang_cc1 %s -E -o - -isystem %S/Inputs/SystemHeaderPrefix | FileCheck %s
|
||||
#include <noline.h>
|
||||
#include <line.h>
|
||||
|
||||
// This tests that "#line" directives in system headers preserve system
|
||||
// header-ness just like GNU line markers that don't have filenames. This was
|
||||
// PR30752.
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
||||
// CHECK: # {{[0-9]+}} "{{.*}}system-header-line-directive.c" 2
|
||||
// CHECK: # 1 "{{.*}}noline.h" 1 3
|
||||
// CHECK: foo();
|
||||
// CHECK: # 4 "{{.*}}system-header-line-directive.c" 2
|
||||
// CHECK: # 1 "{{.*}}line.h" 1 3
|
||||
// The "3" below indicates that "foo.h" is considered a system header.
|
||||
// CHECK: # 1 "foo.h" 3
|
||||
// CHECK: foo();
|
||||
// CHECK: # {{[0-9]+}} "{{.*}}system-header-line-directive.c" 2
|
Loading…
Reference in New Issue