forked from OSchip/llvm-project
Implement MSVC header search algorithm in MicrosoftMode.
Follows algorithm described here: http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx llvm-svn: 198082
This commit is contained in:
parent
558cab2f49
commit
0fafd34a6e
|
@ -300,6 +300,9 @@ def ext_pp_import_directive : Extension<"#import is a language extension">,
|
|||
InGroup<DiagGroup<"import-preprocessor-directive-pedantic">>;
|
||||
def err_pp_import_directive_ms : Error<
|
||||
"#import of type library is an unsupported Microsoft feature">;
|
||||
def ext_pp_include_search_ms : ExtWarn<
|
||||
"#include resolved using non-portable MSVC search rules as: %0">,
|
||||
InGroup<DiagGroup<"msvc-include">>;
|
||||
|
||||
def ext_pp_ident_directive : Extension<"#ident is a language extension">;
|
||||
def ext_pp_include_next_directive : Extension<
|
||||
|
|
|
@ -158,6 +158,8 @@ class HeaderSearch {
|
|||
/// \brief Header-search options used to initialize this header search.
|
||||
IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
|
||||
|
||||
DiagnosticsEngine &Diags;
|
||||
SourceManager &SourceMgr;
|
||||
FileManager &FileMgr;
|
||||
/// \#include search path information. Requests for \#include "x" search the
|
||||
/// directory of the \#including file first, then each directory in SearchDirs
|
||||
|
@ -349,13 +351,15 @@ public:
|
|||
/// \returns If successful, this returns 'UsedDir', the DirectoryLookup member
|
||||
/// the file was found in, or null if not applicable.
|
||||
///
|
||||
/// \param IncludeLoc Used for diagnostics if valid.
|
||||
///
|
||||
/// \param isAngled indicates whether the file reference is a <> reference.
|
||||
///
|
||||
/// \param CurDir If non-null, the file was found in the specified directory
|
||||
/// search location. This is used to implement \#include_next.
|
||||
///
|
||||
/// \param CurFileEnt If non-null, indicates where the \#including file is, in
|
||||
/// case a relative search is needed.
|
||||
/// \param Includers Indicates where the \#including file(s) are, in case
|
||||
/// relative searches are needed. In reverse order of inclusion.
|
||||
///
|
||||
/// \param SearchPath If non-null, will be set to the search path relative
|
||||
/// to which the file was found. If the include path is absolute, SearchPath
|
||||
|
@ -368,10 +372,10 @@ public:
|
|||
/// \param SuggestedModule If non-null, and the file found is semantically
|
||||
/// part of a known module, this will be set to the module that should
|
||||
/// be imported instead of preprocessing/parsing the file found.
|
||||
const FileEntry *LookupFile(StringRef Filename, bool isAngled,
|
||||
const DirectoryLookup *FromDir,
|
||||
const FileEntry *LookupFile(StringRef Filename, SourceLocation IncludeLoc,
|
||||
bool isAngled, const DirectoryLookup *FromDir,
|
||||
const DirectoryLookup *&CurDir,
|
||||
const FileEntry *CurFileEnt,
|
||||
ArrayRef<const FileEntry *> Includers,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Lex/HeaderMap.h"
|
||||
#include "clang/Lex/HeaderSearchOptions.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Capacity.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
|
@ -45,11 +45,11 @@ ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
|
|||
|
||||
HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
|
||||
SourceManager &SourceMgr, DiagnosticsEngine &Diags,
|
||||
const LangOptions &LangOpts,
|
||||
const LangOptions &LangOpts,
|
||||
const TargetInfo *Target)
|
||||
: HSOpts(HSOpts), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
|
||||
ModMap(SourceMgr, Diags, LangOpts, Target, *this)
|
||||
{
|
||||
: HSOpts(HSOpts), Diags(Diags), SourceMgr(SourceMgr),
|
||||
FileMgr(SourceMgr.getFileManager()), FrameworkMap(64),
|
||||
ModMap(SourceMgr, Diags, LangOpts, Target, *this) {
|
||||
AngledDirIdx = 0;
|
||||
SystemDirIdx = 0;
|
||||
NoCurDirSearch = false;
|
||||
|
@ -493,20 +493,15 @@ void HeaderSearch::setTarget(const TargetInfo &Target) {
|
|||
|
||||
/// LookupFile - Given a "foo" or \<foo> reference, look up the indicated file,
|
||||
/// return null on failure. isAngled indicates whether the file reference is
|
||||
/// for system \#include's or not (i.e. using <> instead of ""). CurFileEnt, if
|
||||
/// non-null, indicates where the \#including file is, in case a relative search
|
||||
/// is needed.
|
||||
/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
|
||||
/// non-empty, indicates where the \#including file(s) are, in case a relative
|
||||
/// search is needed. Microsoft mode will pass all \#including files.
|
||||
const FileEntry *HeaderSearch::LookupFile(
|
||||
StringRef Filename,
|
||||
bool isAngled,
|
||||
const DirectoryLookup *FromDir,
|
||||
const DirectoryLookup *&CurDir,
|
||||
const FileEntry *CurFileEnt,
|
||||
SmallVectorImpl<char> *SearchPath,
|
||||
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
|
||||
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
|
||||
ArrayRef<const FileEntry *> Includers, SmallVectorImpl<char> *SearchPath,
|
||||
SmallVectorImpl<char> *RelativePath,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool SkipCache)
|
||||
{
|
||||
ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) {
|
||||
if (!HSOpts->ModuleMapFiles.empty()) {
|
||||
// Preload all explicitly specified module map files. This enables modules
|
||||
// map files lying in a directory structure separate from the header files
|
||||
|
@ -546,44 +541,53 @@ const FileEntry *HeaderSearch::LookupFile(
|
|||
}
|
||||
|
||||
// Unless disabled, check to see if the file is in the #includer's
|
||||
// directory. This has to be based on CurFileEnt, not CurDir, because
|
||||
// CurFileEnt could be a #include of a subdirectory (#include "foo/bar.h") and
|
||||
// a subsequent include of "baz.h" should resolve to "whatever/foo/baz.h".
|
||||
// directory. This cannot be based on CurDir, because each includer could be
|
||||
// a #include of a subdirectory (#include "foo/bar.h") and a subsequent
|
||||
// include of "baz.h" should resolve to "whatever/foo/baz.h".
|
||||
// This search is not done for <> headers.
|
||||
if (CurFileEnt && !isAngled && !NoCurDirSearch) {
|
||||
if (!Includers.empty() && !isAngled && !NoCurDirSearch) {
|
||||
SmallString<1024> TmpDir;
|
||||
// Concatenate the requested file onto the directory.
|
||||
// FIXME: Portability. Filename concatenation should be in sys::Path.
|
||||
TmpDir += CurFileEnt->getDir()->getName();
|
||||
TmpDir.push_back('/');
|
||||
TmpDir.append(Filename.begin(), Filename.end());
|
||||
if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(),/*openFile=*/true)) {
|
||||
// Leave CurDir unset.
|
||||
// This file is a system header or C++ unfriendly if the old file is.
|
||||
//
|
||||
// Note that we only use one of FromHFI/ToHFI at once, due to potential
|
||||
// reallocation of the underlying vector potentially making the first
|
||||
// reference binding dangling.
|
||||
HeaderFileInfo &FromHFI = getFileInfo(CurFileEnt);
|
||||
unsigned DirInfo = FromHFI.DirInfo;
|
||||
bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
|
||||
StringRef Framework = FromHFI.Framework;
|
||||
for (ArrayRef<const FileEntry *>::iterator I(Includers.begin()),
|
||||
E(Includers.end());
|
||||
I != E; ++I) {
|
||||
const FileEntry *Includer = *I;
|
||||
// Concatenate the requested file onto the directory.
|
||||
// FIXME: Portability. Filename concatenation should be in sys::Path.
|
||||
TmpDir = Includer->getDir()->getName();
|
||||
TmpDir.push_back('/');
|
||||
TmpDir.append(Filename.begin(), Filename.end());
|
||||
if (const FileEntry *FE =
|
||||
FileMgr.getFile(TmpDir.str(), /*openFile=*/true)) {
|
||||
// Leave CurDir unset.
|
||||
// This file is a system header or C++ unfriendly if the old file is.
|
||||
//
|
||||
// Note that we only use one of FromHFI/ToHFI at once, due to potential
|
||||
// reallocation of the underlying vector potentially making the first
|
||||
// reference binding dangling.
|
||||
HeaderFileInfo &FromHFI = getFileInfo(Includer);
|
||||
unsigned DirInfo = FromHFI.DirInfo;
|
||||
bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
|
||||
StringRef Framework = FromHFI.Framework;
|
||||
|
||||
HeaderFileInfo &ToHFI = getFileInfo(FE);
|
||||
ToHFI.DirInfo = DirInfo;
|
||||
ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
|
||||
ToHFI.Framework = Framework;
|
||||
HeaderFileInfo &ToHFI = getFileInfo(FE);
|
||||
ToHFI.DirInfo = DirInfo;
|
||||
ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
|
||||
ToHFI.Framework = Framework;
|
||||
|
||||
if (SearchPath != NULL) {
|
||||
StringRef SearchPathRef(CurFileEnt->getDir()->getName());
|
||||
SearchPath->clear();
|
||||
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
|
||||
if (SearchPath != NULL) {
|
||||
StringRef SearchPathRef(Includer->getDir()->getName());
|
||||
SearchPath->clear();
|
||||
SearchPath->append(SearchPathRef.begin(), SearchPathRef.end());
|
||||
}
|
||||
if (RelativePath != NULL) {
|
||||
RelativePath->clear();
|
||||
RelativePath->append(Filename.begin(), Filename.end());
|
||||
}
|
||||
if (I != Includers.begin())
|
||||
Diags.Report(IncludeLoc, diag::ext_pp_include_search_ms)
|
||||
<< FE->getName();
|
||||
return FE;
|
||||
}
|
||||
if (RelativePath != NULL) {
|
||||
RelativePath->clear();
|
||||
RelativePath->append(Filename.begin(), Filename.end());
|
||||
}
|
||||
return FE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -667,18 +671,18 @@ const FileEntry *HeaderSearch::LookupFile(
|
|||
// a header in a framework that is currently being built, and we couldn't
|
||||
// resolve "foo.h" any other way, change the include to <Foo/foo.h>, where
|
||||
// "Foo" is the name of the framework in which the including header was found.
|
||||
if (CurFileEnt && !isAngled && Filename.find('/') == StringRef::npos) {
|
||||
HeaderFileInfo &IncludingHFI = getFileInfo(CurFileEnt);
|
||||
if (!Includers.empty() && !isAngled &&
|
||||
Filename.find('/') == StringRef::npos) {
|
||||
HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front());
|
||||
if (IncludingHFI.IndexHeaderMapHeader) {
|
||||
SmallString<128> ScratchFilename;
|
||||
ScratchFilename += IncludingHFI.Framework;
|
||||
ScratchFilename += '/';
|
||||
ScratchFilename += Filename;
|
||||
|
||||
const FileEntry *Result = LookupFile(ScratchFilename, /*isAngled=*/true,
|
||||
FromDir, CurDir, CurFileEnt,
|
||||
SearchPath, RelativePath,
|
||||
SuggestedModule);
|
||||
|
||||
const FileEntry *Result = LookupFile(
|
||||
ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
|
||||
Includers.front(), SearchPath, RelativePath, SuggestedModule);
|
||||
std::pair<unsigned, unsigned> &CacheLookup
|
||||
= LookupFileCache.GetOrCreateValue(Filename).getValue();
|
||||
CacheLookup.second
|
||||
|
|
|
@ -560,12 +560,12 @@ const FileEntry *Preprocessor::LookupFile(
|
|||
SmallVectorImpl<char> *RelativePath,
|
||||
ModuleMap::KnownHeader *SuggestedModule,
|
||||
bool SkipCache) {
|
||||
// If the header lookup mechanism may be relative to the current file, pass in
|
||||
// info about where the current file is.
|
||||
const FileEntry *CurFileEnt = 0;
|
||||
// If the header lookup mechanism may be relative to the current inclusion
|
||||
// stack, record the parent #includes.
|
||||
SmallVector<const FileEntry *, 16> Includers;
|
||||
if (!FromDir) {
|
||||
FileID FID = getCurrentFileLexer()->getFileID();
|
||||
CurFileEnt = SourceMgr.getFileEntryForID(FID);
|
||||
const FileEntry *FileEnt = SourceMgr.getFileEntryForID(FID);
|
||||
|
||||
// If there is no file entry associated with this file, it must be the
|
||||
// predefines buffer. Any other file is not lexed with a normal lexer, so
|
||||
|
@ -573,17 +573,31 @@ const FileEntry *Preprocessor::LookupFile(
|
|||
// predefines buffer, resolve #include references (which come from the
|
||||
// -include command line argument) as if they came from the main file, this
|
||||
// affects file lookup etc.
|
||||
if (CurFileEnt == 0) {
|
||||
FID = SourceMgr.getMainFileID();
|
||||
CurFileEnt = SourceMgr.getFileEntryForID(FID);
|
||||
if (!FileEnt)
|
||||
FileEnt = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
|
||||
|
||||
if (FileEnt)
|
||||
Includers.push_back(FileEnt);
|
||||
|
||||
// MSVC searches the current include stack from top to bottom for
|
||||
// headers included by quoted include directives.
|
||||
// See: http://msdn.microsoft.com/en-us/library/36k2cdd4.aspx
|
||||
if (LangOpts.MicrosoftMode && !isAngled) {
|
||||
for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) {
|
||||
IncludeStackInfo &ISEntry = IncludeMacroStack[e - i - 1];
|
||||
if (IsFileLexer(ISEntry))
|
||||
if ((FileEnt = SourceMgr.getFileEntryForID(
|
||||
ISEntry.ThePPLexer->getFileID())))
|
||||
Includers.push_back(FileEnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do a standard file entry lookup.
|
||||
CurDir = CurDirLookup;
|
||||
const FileEntry *FE = HeaderInfo.LookupFile(
|
||||
Filename, isAngled, FromDir, CurDir, CurFileEnt,
|
||||
SearchPath, RelativePath, SuggestedModule, SkipCache);
|
||||
Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
|
||||
RelativePath, SuggestedModule, SkipCache);
|
||||
if (FE) {
|
||||
if (SuggestedModule)
|
||||
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
|
||||
|
@ -591,6 +605,7 @@ const FileEntry *Preprocessor::LookupFile(
|
|||
return FE;
|
||||
}
|
||||
|
||||
const FileEntry *CurFileEnt;
|
||||
// Otherwise, see if this is a subframework header. If so, this is relative
|
||||
// to one of the headers on the #include stack. Walk the list of the current
|
||||
// headers on the #include stack and pass them to HeaderInfo.
|
||||
|
|
|
@ -335,7 +335,7 @@ bool InclusionRewriter::HandleHasInclude(
|
|||
bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
|
||||
const DirectoryLookup *CurDir;
|
||||
const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
|
||||
Filename, isAngled, 0, CurDir,
|
||||
Filename, SourceLocation(), isAngled, 0, CurDir,
|
||||
PP.getSourceManager().getFileEntryForID(FileId), 0, 0, 0, false);
|
||||
|
||||
FileExists = File != 0;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: %clang_cc1 -I%S/microsoft-header-search %s -fms-compatibility -verify
|
||||
|
||||
// expected-warning@microsoft-header-search/a/findme.h:3 {{findme.h successfully included using MS search rules}}
|
||||
// expected-warning@microsoft-header-search/a/b/include3.h:3 {{#include resolved using non-portable MSVC search rules as}}
|
||||
|
||||
#include "microsoft-header-search/include1.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include "findme.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#warning findme.h successfully included using MS search rules
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "b/include3.h"
|
||||
#pragma once
|
||||
|
||||
#include "b/include3.h"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#error Wrong findme.h included, MSVC header search incorrect
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "a/include2.h"
|
||||
#pragma once
|
||||
|
||||
#include "a/include2.h"
|
Loading…
Reference in New Issue