From 269c232e67ee79342762660d7a19ff36b373cc1e Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 25 Jun 2006 06:23:00 +0000 Subject: [PATCH] implement #pragma GCC dependency llvm-svn: 38574 --- clang/Basic/FileManager.cpp | 5 +- clang/Lex/Lexer.cpp | 56 +++++++----- clang/Lex/Preprocessor.cpp | 85 ++++++++++++++----- clang/include/clang/Basic/DiagnosticKinds.def | 2 + clang/include/clang/Basic/FileManager.h | 2 + clang/include/clang/Lex/Lexer.h | 5 +- clang/include/clang/Lex/Preprocessor.h | 1 + 7 files changed, 110 insertions(+), 46 deletions(-) diff --git a/clang/Basic/FileManager.cpp b/clang/Basic/FileManager.cpp index 7044a70465f3..50efc7c2b281 100644 --- a/clang/Basic/FileManager.cpp +++ b/clang/Basic/FileManager.cpp @@ -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; diff --git a/clang/Lex/Lexer.cpp b/clang/Lex/Lexer.cpp index cd514e3308de..b183c4d1ea9d 100644 --- a/clang/Lex/Lexer.cpp +++ b/clang/Lex/Lexer.cpp @@ -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 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 diff --git a/clang/Lex/Preprocessor.cpp b/clang/Lex/Preprocessor.cpp index bec62cafe5ed..94659cbb8d19 100644 --- a/clang/Lex/Preprocessor.cpp +++ b/clang/Lex/Preprocessor.cpp @@ -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 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 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 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"))); } diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index a4fd880b942b..fdf74434f18e 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -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") diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index cfa72b3f1dcb..f7b2c4065ce6 100644 --- a/clang/include/clang/Basic/FileManager.h +++ b/clang/include/clang/Basic/FileManager.h @@ -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. /// diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h index caf16f07c9a9..499b5a8e8ce4 100644 --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -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); }; diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 06143062c6d9..8c4924671974 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -433,6 +433,7 @@ public: void HandlePragmaOnce(LexerToken &OnceTok); void HandlePragmaPoison(LexerToken &PoisonTok); void HandlePragmaSystemHeader(LexerToken &SysHeaderTok); + void HandlePragmaDependency(LexerToken &DependencyTok); }; } // end namespace clang