Index: include/clang/Lex/Lexer.h =================================================================== --- include/clang/Lex/Lexer.h +++ include/clang/Lex/Lexer.h @@ -438,6 +438,21 @@ return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts); } + /// \brief Finds the last directive in a given file. + /// \param FixitLoc stores the result. + /// \param Directive specifies the desired directive. + /// \return returns false if the directive is not found and + /// \p FixitLoc is defaulted to the start of the file. + static bool findLastDirective(const FileID ID, const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation &LastDirectiveLoc, + llvm::StringRef Directive); + + /// \brief Returns the location of the next line adjacent to the source + /// location + /// the onus is on the caller to check that the location is valid + static SourceLocation getLineAfterToken(const SourceLocation &Loc, + const SourceManager &SM); //===--------------------------------------------------------------------===// // Internal implementation interfaces. private: Index: lib/Lex/Lexer.cpp =================================================================== --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1010,6 +1010,78 @@ return isIdentifierBody(c, LangOpts.DollarIdents); } +bool Lexer::findLastDirective(const FileID ID, const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation &LastDirectiveLoc, + llvm::StringRef Directive) { + + bool FoundDirective = false; + // Get the file buffer. + bool InvalidTemp = false; + llvm::MemoryBuffer *FileBuf = SM.getBuffer(ID, &InvalidTemp); + if (InvalidTemp) { + LastDirectiveLoc = SourceLocation(); + return false; + } + + // Default location for the Last 'include' directive is start of file. + LastDirectiveLoc = SM.getLocForStartOfFile(ID); + + // Find the Location of the last #include directive in the file. + Lexer IncludeLexer(ID, FileBuf, SM, LangOpts); + while (1) { + Token Tok; + IncludeLexer.LexFromRawLexer(Tok); + if (Tok.is(tok::eof)) + break; + if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) { + IncludeLexer.LexFromRawLexer(Tok); + if (Tok.getRawIdentifier() == Directive && Tok.getLocation().isValid()) { + FoundDirective = true; + LastDirectiveLoc = Tok.getLocation(); + } + continue; + } + // If any other identifier is encountered we've passed the 'includes'. + if (tok::isAnyIdentifier(Tok.getKind())) { + break; + } + } + + if (FoundDirective) + return true; + else + return false; +} + +SourceLocation clang::Lexer::getLineAfterToken(const SourceLocation &Loc, + const SourceManager &SM) { + + SourceLocation FileLoc = SM.getFileLoc(Loc); + FileID ID = SM.getFileID(Loc); + + bool InvalidTemp = false; + llvm::MemoryBuffer *FileBuf = SM.getBuffer(ID, &InvalidTemp); + if (InvalidTemp) { + return SourceLocation(); + } + + const char *BuffEnd = FileBuf->getBufferEnd(); + const char *RawBuffer = SM.getCharacterData(FileLoc); + unsigned char C = *RawBuffer; + unsigned OffSet = 0; + + while (1) { + if (C == '\n' || C == '\r') + break; + if (RawBuffer == BuffEnd) + return SourceLocation(); + C = *(++RawBuffer); + OffSet++; + } + OffSet++; + return Loc.getLocWithOffset(OffSet); +} //===----------------------------------------------------------------------===// // Diagnostics forwarding code. Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -1664,6 +1664,7 @@ llvm_unreachable("unhandled error kind"); } + /// LazilyCreateBuiltin - The specified Builtin-ID was first used at /// file scope. lazily create a decl for it. ForRedeclaration is true /// if we're creating this built-in in anticipation of redeclaring the @@ -1678,45 +1679,23 @@ if (Error) { if (ForRedeclaration) Diag(Loc, diag::warn_implicit_decl_requires_sysheader) - << getHeaderName(Error) - << Context.BuiltinInfo.GetName(ID); + << getHeaderName(Error) << Context.BuiltinInfo.GetName(ID); return nullptr; } - //get the file buffer - FileID FileID = SourceMgr.getFileID(Loc); - llvm::MemoryBuffer* FileBuf = SourceMgr.getBuffer(FileID); - SourceLocation LastIncludeLoc = SourceMgr.getLocForStartOfFile(FileID); - - //Find the Location of the last #include directive in the file - Lexer IncludeLexer(FileID,FileBuf,SourceMgr,LangOpts); - while (1) { - Token Tok; - IncludeLexer.LexFromRawLexer(Tok); - if (Tok.is(tok::eof)) - break; - if (Tok.is(tok::hash)){ - IncludeLexer.LexFromRawLexer(Tok); - if(Tok.getRawIdentifier() == "include" && Tok.getLocation().isValid()) - LastIncludeLoc = Tok.getLocation(); - } - } - - - //Get the location of the line after the last #include directive - PresumedLoc PLoc = SourceMgr.getPresumedLoc(LastIncludeLoc); - SourceLocation FixitLoc = SourceMgr.translateLineCol(FileID,PLoc.getLine()+1,PLoc.getColumn()); - if (FixitLoc.isInvalid()){ - FixitLoc = LastIncludeLoc; - } - + SourceLocation FileLoc = SourceMgr.getFileLoc(Loc); + FileID FixitFileID = SourceMgr.getFileID(FileLoc); + SourceLocation FixitLoc; + if (Lexer::findLastDirective(FixitFileID, SourceMgr, LangOpts, FixitLoc, + "include")) + FixitLoc = Lexer::getLineAfterToken(FixitLoc, SourceMgr); if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(ID)) { Diag(Loc, diag::ext_implicit_lib_function_decl) << Context.BuiltinInfo.GetName(ID) << R; - //Build 'insert missing header' string + //Build 'insert missing header' string. std::string FixitString = "#include <"; FixitString.append(Context.BuiltinInfo.getHeaderName(ID)); FixitString.append(">"); Index: test/Sema/implicit-builtin-decl.c =================================================================== --- test/Sema/implicit-builtin-decl.c +++ test/Sema/implicit-builtin-decl.c @@ -3,7 +3,7 @@ void f() { int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring library function 'malloc' with type}} \ - // expected-note@-3{{include the header or explicitly provide a declaration for 'malloc'}} \ + // expected-note@-4{{include the header or explicitly provide a declaration for 'malloc'}} \ // expected-note{{'malloc' is a builtin with type 'void *}} }