implement #pragma GCC dependency

llvm-svn: 38574
This commit is contained in:
Chris Lattner 2006-06-25 06:23:00 +00:00
parent ba6df9122f
commit 269c232e67
7 changed files with 110 additions and 46 deletions

View File

@ -113,11 +113,12 @@ const FileEntry *FileManager::getFile(const std::string &Filename) {
if (UFE) // Already have an entry with this inode, return it.
return Ent = UFE;
// Otherwise, we don't have this directory yet, add it.
FileEntry *FE = new FileEntry();
FE->Size = StatBuf.st_size;
FE->Name = Filename;
FE->Size = StatBuf.st_size;
FE->ModTime = StatBuf.st_mtime;
FE->Dir = DirInfo;
FE->UID = NextFileUID++;
return Ent = UFE = FE;

View File

@ -783,7 +783,7 @@ void Lexer::SkipBlockComment(LexerToken &Result, const char *CurPtr) {
/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
/// (potentially) macro expand the filename.
void Lexer::LexIncludeFilename(LexerToken &Result) {
std::string Lexer::LexIncludeFilename(LexerToken &FilenameTok) {
assert(ParsingPreprocessorDirective &&
ParsingFilename == false &&
"Must be in a preprocessing directive!");
@ -791,33 +791,49 @@ void Lexer::LexIncludeFilename(LexerToken &Result) {
// We are now parsing a filename!
ParsingFilename = true;
// There should be exactly two tokens here if everything is good: first the
// filename, then the EOM.
Lex(Result);
// Lex the filename.
Lex(FilenameTok);
// We should have gotten the filename now.
ParsingFilename = false;
// No filename?
if (Result.getKind() == tok::eom) {
PP.Diag(Result, diag::err_pp_expects_filename);
return;
if (FilenameTok.getKind() == tok::eom) {
PP.Diag(FilenameTok, diag::err_pp_expects_filename);
return "";
}
// Verify that there is nothing after the filename, other than EOM. Use the
// preprocessor to lex this in case lexing the filename entered a macro.
LexerToken EndTok;
PP.Lex(EndTok);
if (EndTok.getKind() != tok::eom) {
PP.Diag(EndTok, diag::ext_pp_extra_tokens_at_eol, "#include");
// Lex until the end of the preprocessor directive line.
while (EndTok.getKind() != tok::eom)
PP.Lex(EndTok);
Result.SetKind(tok::eom);
// Get the text form of the filename.
std::string Filename = PP.getSpelling(FilenameTok);
assert(!Filename.empty() && "Can't have tokens with empty spellings!");
// Make sure the filename is <x> or "x".
if (Filename[0] == '<') {
if (Filename[Filename.size()-1] != '>') {
PP.Diag(FilenameTok, diag::err_pp_expects_filename);
FilenameTok.SetKind(tok::eom);
return "";
}
} else if (Filename[0] == '"') {
if (Filename[Filename.size()-1] != '"') {
PP.Diag(FilenameTok, diag::err_pp_expects_filename);
FilenameTok.SetKind(tok::eom);
return "";
}
} else {
PP.Diag(FilenameTok, diag::err_pp_expects_filename);
FilenameTok.SetKind(tok::eom);
return "";
}
// Diagnose #include "" as invalid.
if (Filename.size() == 2) {
PP.Diag(FilenameTok, diag::err_pp_empty_filename);
FilenameTok.SetKind(tok::eom);
return "";
}
return Filename;
}
/// ReadToEndOfLine - Read the rest of the current preprocessor line as an

View File

@ -938,41 +938,26 @@ void Preprocessor::HandleIncludeDirective(LexerToken &IncludeTok,
bool isImport) {
++NumIncluded;
LexerToken FilenameTok;
CurLexer->LexIncludeFilename(FilenameTok);
std::string Filename = CurLexer->LexIncludeFilename(FilenameTok);
// If the token kind is EOM, the error has already been diagnosed.
if (FilenameTok.getKind() == tok::eom)
return;
// Verify that there is nothing after the filename, other than EOM. Use the
// preprocessor to lex this in case lexing the filename entered a macro.
CheckEndOfDirective("#include");
// Check that we don't have infinite #include recursion.
if (IncludeStack.size() == MaxAllowedIncludeStackDepth-1)
return Diag(FilenameTok, diag::err_pp_include_too_deep);
// Get the text form of the filename.
std::string Filename = getSpelling(FilenameTok);
assert(!Filename.empty() && "Can't have tokens with empty spellings!");
// Make sure the filename is <x> or "x".
bool isAngled;
if (Filename[0] == '<') {
isAngled = true;
if (Filename[Filename.size()-1] != '>')
return Diag(FilenameTok, diag::err_pp_expects_filename);
} else if (Filename[0] == '"') {
isAngled = false;
if (Filename[Filename.size()-1] != '"')
return Diag(FilenameTok, diag::err_pp_expects_filename);
} else {
return Diag(FilenameTok, diag::err_pp_expects_filename);
}
// Find out whether the filename is <x> or "x".
bool isAngled = Filename[0] == '<';
// Remove the quotes.
Filename = std::string(Filename.begin()+1, Filename.end()-1);
// Diagnose #include "" as invalid.
if (Filename.empty())
return Diag(FilenameTok, diag::err_pp_empty_filename);
// Search include directories.
const DirectoryLookup *CurDir;
const FileEntry *File = LookupFile(Filename, isAngled, LookupFrom, CurDir);
@ -1325,6 +1310,8 @@ void Preprocessor::HandlePragmaPoison(LexerToken &PoisonTok) {
}
}
/// HandlePragmaSystemHeader - Implement #pragma GCC system_header. We know
/// that the whole directive has been parsed.
void Preprocessor::HandlePragmaSystemHeader(LexerToken &SysHeaderTok) {
if (IncludeStack.empty()) {
Diag(SysHeaderTok, diag::pp_pragma_sysheader_in_main_file);
@ -1343,6 +1330,52 @@ void Preprocessor::HandlePragmaSystemHeader(LexerToken &SysHeaderTok) {
SystemHeaderPragma, DirectoryLookup::SystemHeaderDir);
}
/// HandlePragmaDependency - Handle #pragma GCC dependency "foo" blah.
///
void Preprocessor::HandlePragmaDependency(LexerToken &DependencyTok) {
LexerToken FilenameTok;
std::string Filename = CurLexer->LexIncludeFilename(FilenameTok);
// If the token kind is EOM, the error has already been diagnosed.
if (FilenameTok.getKind() == tok::eom)
return;
// Find out whether the filename is <x> or "x".
bool isAngled = Filename[0] == '<';
// Remove the quotes.
Filename = std::string(Filename.begin()+1, Filename.end()-1);
// Search include directories.
const DirectoryLookup *CurDir;
const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir);
if (File == 0)
return Diag(FilenameTok, diag::err_pp_file_not_found);
Lexer *TheLexer = CurLexer;
if (TheLexer == 0) {
assert(!IncludeStack.empty() && "No current lexer?");
TheLexer = IncludeStack.back().TheLexer;
}
const FileEntry *CurFile =
SourceMgr.getFileEntryForFileID(TheLexer->getCurFileID());
// If this file is older than the file it depends on, emit a diagnostic.
if (CurFile && CurFile->getModificationTime() < File->getModificationTime()) {
// Lex tokens at the end of the message and include them in the message.
std::string Message;
Lex(DependencyTok);
while (DependencyTok.getKind() != tok::eom) {
Message += getSpelling(DependencyTok) + " ";
Lex(DependencyTok);
}
Message.erase(Message.end()-1);
Diag(FilenameTok, diag::pp_out_of_date_dependency, Message);
}
}
/// AddPragmaHandler - Add the specified pragma handler to the preprocessor.
/// If 'Namespace' is non-null, then it is a token required to exist on the
/// pragma line before the pragma string starts, e.g. "STDC" or "GCC".
@ -1398,6 +1431,12 @@ struct PragmaSystemHeaderHandler : public PragmaHandler {
PP.CheckEndOfDirective("#pragma");
}
};
struct PragmaDependencyHandler : public PragmaHandler {
PragmaDependencyHandler(const IdentifierTokenInfo *ID) : PragmaHandler(ID) {}
virtual void HandlePragma(Preprocessor &PP, LexerToken &DepToken) {
PP.HandlePragmaDependency(DepToken);
}
};
}
@ -1408,4 +1447,6 @@ void Preprocessor::RegisterBuiltinPragmas() {
AddPragmaHandler("GCC", new PragmaPoisonHandler(getIdentifierInfo("poison")));
AddPragmaHandler("GCC", new PragmaSystemHeaderHandler(
getIdentifierInfo("system_header")));
AddPragmaHandler("GCC", new PragmaDependencyHandler(
getIdentifierInfo("dependency")));
}

View File

@ -92,6 +92,8 @@ DIAG(pp_pragma_sysheader_in_main_file, WARNING,
"#pragma system_header ignored in main file")
DIAG(pp_poisoning_existing_macro, WARNING,
"poisoning existing macro")
DIAG(pp_out_of_date_dependency, WARNING,
"current file is older than dependency %s")
DIAG(ext_pp_import_directive, EXTENSION,
"#import is a language extension")

View File

@ -38,6 +38,7 @@ public:
class FileEntry {
std::string Name; // Name of the directory.
off_t Size; // File size in bytes.
time_t ModTime; // Modification time of file.
const DirectoryEntry *Dir; // Directory file lives in.
unsigned UID; // A unique (small) ID for the file.
FileEntry() {}
@ -47,6 +48,7 @@ public:
const std::string &getName() const { return Name; }
off_t getSize() const { return Size; }
unsigned getUID() const { return UID; }
time_t getModificationTime() const { return ModTime; }
/// getDir - Return the directory the file lives in.
///

View File

@ -288,8 +288,9 @@ private:
/// LexIncludeFilename - After the preprocessor has parsed a #include, lex and
/// (potentially) macro expand the filename. If the sequence parsed is not
/// lexically legal, emit a diagnostic and return a result EOM token.
void LexIncludeFilename(LexerToken &Result);
/// lexically legal, emit a diagnostic and return a result EOM token. Return
/// the spelled and checked filename.
std::string LexIncludeFilename(LexerToken &Result);
};

View File

@ -433,6 +433,7 @@ public:
void HandlePragmaOnce(LexerToken &OnceTok);
void HandlePragmaPoison(LexerToken &PoisonTok);
void HandlePragmaSystemHeader(LexerToken &SysHeaderTok);
void HandlePragmaDependency(LexerToken &DependencyTok);
};
} // end namespace clang