2017-12-07 07:18:41 +08:00
|
|
|
//===- ModuleMap.cpp - Describe the layout of modules ---------------------===//
|
2011-11-12 03:10:28 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-11-12 03:10:28 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the ModuleMap implementation, which describes the layout
|
|
|
|
// of a module as it relates to headers.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
#include "clang/Lex/ModuleMap.h"
|
2013-02-09 06:30:41 +08:00
|
|
|
#include "clang/Basic/CharInfo.h"
|
2011-11-12 03:10:28 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
|
#include "clang/Basic/FileManager.h"
|
2017-12-07 07:18:41 +08:00
|
|
|
#include "clang/Basic/LLVM.h"
|
|
|
|
#include "clang/Basic/LangOptions.h"
|
|
|
|
#include "clang/Basic/Module.h"
|
|
|
|
#include "clang/Basic/SourceLocation.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
2011-11-12 03:10:28 +08:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2013-03-14 05:13:51 +08:00
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
2014-12-10 11:09:48 +08:00
|
|
|
#include "clang/Lex/HeaderSearchOptions.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Lex/LexDiagnostic.h"
|
|
|
|
#include "clang/Lex/Lexer.h"
|
|
|
|
#include "clang/Lex/LiteralSupport.h"
|
2017-12-07 07:18:41 +08:00
|
|
|
#include "clang/Lex/Token.h"
|
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/None.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringMap.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2011-11-12 03:10:28 +08:00
|
|
|
#include "llvm/Support/Allocator.h"
|
2017-12-07 07:18:41 +08:00
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2013-06-12 06:15:02 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2018-10-10 21:27:25 +08:00
|
|
|
#include "llvm/Support/VirtualFileSystem.h"
|
2011-11-12 03:10:28 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-12-07 07:18:41 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstring>
|
|
|
|
#include <string>
|
|
|
|
#include <system_error>
|
|
|
|
#include <utility>
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2018-12-29 10:02:30 +08:00
|
|
|
void ModuleMapCallbacks::anchor() {}
|
|
|
|
|
2018-04-17 03:42:32 +08:00
|
|
|
void ModuleMap::resolveLinkAsDependencies(Module *Mod) {
|
|
|
|
auto PendingLinkAs = PendingLinkAsModule.find(Mod->Name);
|
|
|
|
if (PendingLinkAs != PendingLinkAsModule.end()) {
|
|
|
|
for (auto &Name : PendingLinkAs->second) {
|
|
|
|
auto *M = findModule(Name.getKey());
|
|
|
|
if (M)
|
|
|
|
M->UseExportAsModuleLinkName = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleMap::addLinkAsDependency(Module *Mod) {
|
|
|
|
if (findModule(Mod->ExportAsModule))
|
|
|
|
Mod->UseExportAsModuleLinkName = true;
|
|
|
|
else
|
|
|
|
PendingLinkAsModule[Mod->ExportAsModule].insert(Mod->Name);
|
|
|
|
}
|
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
Module::HeaderKind ModuleMap::headerRoleToKind(ModuleHeaderRole Role) {
|
|
|
|
switch ((int)Role) {
|
|
|
|
default: llvm_unreachable("unknown header role");
|
|
|
|
case NormalHeader:
|
|
|
|
return Module::HK_Normal;
|
|
|
|
case PrivateHeader:
|
|
|
|
return Module::HK_Private;
|
|
|
|
case TextualHeader:
|
|
|
|
return Module::HK_Textual;
|
|
|
|
case PrivateHeader | TextualHeader:
|
|
|
|
return Module::HK_PrivateTextual;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ModuleMap::ModuleHeaderRole
|
|
|
|
ModuleMap::headerKindToRole(Module::HeaderKind Kind) {
|
|
|
|
switch ((int)Kind) {
|
|
|
|
case Module::HK_Normal:
|
|
|
|
return NormalHeader;
|
|
|
|
case Module::HK_Private:
|
|
|
|
return PrivateHeader;
|
|
|
|
case Module::HK_Textual:
|
|
|
|
return TextualHeader;
|
|
|
|
case Module::HK_PrivateTextual:
|
|
|
|
return ModuleHeaderRole(PrivateHeader | TextualHeader);
|
|
|
|
case Module::HK_Excluded:
|
|
|
|
llvm_unreachable("unexpected header kind");
|
|
|
|
}
|
|
|
|
llvm_unreachable("unknown header kind");
|
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
Module::ExportDecl
|
|
|
|
ModuleMap::resolveExport(Module *Mod,
|
2011-12-02 09:47:07 +08:00
|
|
|
const Module::UnresolvedExportDecl &Unresolved,
|
2013-02-20 03:58:45 +08:00
|
|
|
bool Complain) const {
|
2011-12-06 01:28:06 +08:00
|
|
|
// We may have just a wildcard.
|
|
|
|
if (Unresolved.Id.empty()) {
|
|
|
|
assert(Unresolved.Wildcard && "Invalid unresolved export");
|
2014-05-18 07:10:59 +08:00
|
|
|
return Module::ExportDecl(nullptr, true);
|
2011-12-06 01:28:06 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-03-21 05:10:35 +08:00
|
|
|
// Resolve the module-id.
|
|
|
|
Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain);
|
|
|
|
if (!Context)
|
2017-12-07 07:18:41 +08:00
|
|
|
return {};
|
2013-03-21 05:10:35 +08:00
|
|
|
|
|
|
|
return Module::ExportDecl(Context, Unresolved.Wildcard);
|
|
|
|
}
|
|
|
|
|
|
|
|
Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
|
|
|
|
bool Complain) const {
|
2011-12-02 09:47:07 +08:00
|
|
|
// Find the starting module.
|
2013-03-21 05:10:35 +08:00
|
|
|
Module *Context = lookupModuleUnqualified(Id[0].first, Mod);
|
2011-12-02 09:47:07 +08:00
|
|
|
if (!Context) {
|
|
|
|
if (Complain)
|
2013-12-17 18:31:37 +08:00
|
|
|
Diags.Report(Id[0].second, diag::err_mmap_missing_module_unqualified)
|
2013-03-21 05:10:35 +08:00
|
|
|
<< Id[0].first << Mod->getFullModuleName();
|
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2011-12-02 09:47:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Dig into the module path.
|
2013-03-21 05:10:35 +08:00
|
|
|
for (unsigned I = 1, N = Id.size(); I != N; ++I) {
|
|
|
|
Module *Sub = lookupModuleQualified(Id[I].first, Context);
|
2011-12-02 09:47:07 +08:00
|
|
|
if (!Sub) {
|
|
|
|
if (Complain)
|
2013-12-17 18:31:37 +08:00
|
|
|
Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)
|
2013-03-21 05:10:35 +08:00
|
|
|
<< Id[I].first << Context->getFullModuleName()
|
|
|
|
<< SourceRange(Id[0].second, Id[I-1].second);
|
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2011-12-02 09:47:07 +08:00
|
|
|
}
|
2013-03-21 05:10:35 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
Context = Sub;
|
|
|
|
}
|
2013-03-21 05:10:35 +08:00
|
|
|
|
|
|
|
return Context;
|
2011-12-02 09:47:07 +08:00
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
/// Append to \p Paths the set of paths needed to get to the
|
2017-05-26 08:01:53 +08:00
|
|
|
/// subframework in which the given module lives.
|
|
|
|
static void appendSubframeworkPaths(Module *Mod,
|
|
|
|
SmallVectorImpl<char> &Path) {
|
|
|
|
// Collect the framework names from the given module to the top-level module.
|
|
|
|
SmallVector<StringRef, 2> Paths;
|
|
|
|
for (; Mod; Mod = Mod->Parent) {
|
|
|
|
if (Mod->IsFramework)
|
|
|
|
Paths.push_back(Mod->Name);
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2017-05-26 08:01:53 +08:00
|
|
|
if (Paths.empty())
|
|
|
|
return;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2017-05-26 08:01:53 +08:00
|
|
|
// Add Frameworks/Name.framework for each subframework.
|
|
|
|
for (unsigned I = Paths.size() - 1; I != 0; --I)
|
|
|
|
llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework");
|
|
|
|
}
|
|
|
|
|
2018-06-01 09:26:18 +08:00
|
|
|
const FileEntry *ModuleMap::findHeader(
|
|
|
|
Module *M, const Module::UnresolvedHeaderDirective &Header,
|
|
|
|
SmallVectorImpl<char> &RelativePathName, bool &NeedsFramework) {
|
|
|
|
// Search for the header file within the module's home directory.
|
|
|
|
auto *Directory = M->Directory;
|
|
|
|
SmallString<128> FullPathName(Directory->getName());
|
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
auto GetFile = [&](StringRef Filename) -> const FileEntry * {
|
2019-08-02 05:31:56 +08:00
|
|
|
auto File = SourceMgr.getFileManager().getFile(Filename);
|
2017-06-02 09:55:39 +08:00
|
|
|
if (!File ||
|
2019-08-02 05:31:56 +08:00
|
|
|
(Header.Size && (*File)->getSize() != *Header.Size) ||
|
|
|
|
(Header.ModTime && (*File)->getModificationTime() != *Header.ModTime))
|
2017-06-02 09:55:39 +08:00
|
|
|
return nullptr;
|
2019-08-02 05:31:56 +08:00
|
|
|
return *File;
|
2017-06-02 09:55:39 +08:00
|
|
|
};
|
|
|
|
|
2018-06-01 09:26:18 +08:00
|
|
|
auto GetFrameworkFile = [&]() -> const FileEntry * {
|
|
|
|
unsigned FullPathLength = FullPathName.size();
|
2017-05-26 08:01:53 +08:00
|
|
|
appendSubframeworkPaths(M, RelativePathName);
|
|
|
|
unsigned RelativePathLength = RelativePathName.size();
|
|
|
|
|
|
|
|
// Check whether this file is in the public headers.
|
|
|
|
llvm::sys::path::append(RelativePathName, "Headers", Header.FileName);
|
|
|
|
llvm::sys::path::append(FullPathName, RelativePathName);
|
2017-06-02 09:55:39 +08:00
|
|
|
if (auto *File = GetFile(FullPathName))
|
2017-05-26 08:01:53 +08:00
|
|
|
return File;
|
|
|
|
|
|
|
|
// Check whether this file is in the private headers.
|
|
|
|
// Ideally, private modules in the form 'FrameworkName.Private' should
|
|
|
|
// be defined as 'module FrameworkName.Private', and not as
|
|
|
|
// 'framework module FrameworkName.Private', since a 'Private.Framework'
|
|
|
|
// does not usually exist. However, since both are currently widely used
|
|
|
|
// for private modules, make sure we find the right path in both cases.
|
|
|
|
if (M->IsFramework && M->Name == "Private")
|
|
|
|
RelativePathName.clear();
|
|
|
|
else
|
|
|
|
RelativePathName.resize(RelativePathLength);
|
|
|
|
FullPathName.resize(FullPathLength);
|
|
|
|
llvm::sys::path::append(RelativePathName, "PrivateHeaders",
|
|
|
|
Header.FileName);
|
|
|
|
llvm::sys::path::append(FullPathName, RelativePathName);
|
2017-06-02 09:55:39 +08:00
|
|
|
return GetFile(FullPathName);
|
2018-06-01 09:26:18 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
if (llvm::sys::path::is_absolute(Header.FileName)) {
|
|
|
|
RelativePathName.clear();
|
|
|
|
RelativePathName.append(Header.FileName.begin(), Header.FileName.end());
|
|
|
|
return GetFile(Header.FileName);
|
2017-05-26 08:01:53 +08:00
|
|
|
}
|
|
|
|
|
2018-06-01 09:26:18 +08:00
|
|
|
if (M->isPartOfFramework())
|
|
|
|
return GetFrameworkFile();
|
|
|
|
|
2017-05-26 08:01:53 +08:00
|
|
|
// Lookup for normal headers.
|
|
|
|
llvm::sys::path::append(RelativePathName, Header.FileName);
|
|
|
|
llvm::sys::path::append(FullPathName, RelativePathName);
|
2018-06-01 09:26:18 +08:00
|
|
|
auto *NormalHdrFile = GetFile(FullPathName);
|
|
|
|
|
|
|
|
if (M && !NormalHdrFile && Directory->getName().endswith(".framework")) {
|
|
|
|
// The lack of 'framework' keyword in a module declaration it's a simple
|
|
|
|
// mistake we can diagnose when the header exists within the proper
|
|
|
|
// framework style path.
|
|
|
|
FullPathName.assign(Directory->getName());
|
|
|
|
RelativePathName.clear();
|
2018-06-01 22:16:18 +08:00
|
|
|
if (GetFrameworkFile()) {
|
2018-06-01 09:26:18 +08:00
|
|
|
Diags.Report(Header.FileNameLoc,
|
|
|
|
diag::warn_mmap_incomplete_framework_module_declaration)
|
|
|
|
<< Header.FileName << M->getFullModuleName();
|
|
|
|
NeedsFramework = true;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NormalHdrFile;
|
2017-05-26 08:01:53 +08:00
|
|
|
}
|
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
void ModuleMap::resolveHeader(Module *Mod,
|
2018-06-01 09:26:18 +08:00
|
|
|
const Module::UnresolvedHeaderDirective &Header,
|
|
|
|
bool &NeedsFramework) {
|
2017-06-02 09:55:39 +08:00
|
|
|
SmallString<128> RelativePathName;
|
2018-06-01 09:26:18 +08:00
|
|
|
if (const FileEntry *File =
|
|
|
|
findHeader(Mod, Header, RelativePathName, NeedsFramework)) {
|
2017-06-02 09:55:39 +08:00
|
|
|
if (Header.IsUmbrella) {
|
|
|
|
const DirectoryEntry *UmbrellaDir = File->getDir();
|
|
|
|
if (Module *UmbrellaMod = UmbrellaDirs[UmbrellaDir])
|
|
|
|
Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
|
|
|
|
<< UmbrellaMod->getFullModuleName();
|
|
|
|
else
|
|
|
|
// Record this umbrella header.
|
|
|
|
setUmbrellaHeader(Mod, File, RelativePathName.str());
|
|
|
|
} else {
|
|
|
|
Module::Header H = {RelativePathName.str(), File};
|
|
|
|
if (Header.Kind == Module::HK_Excluded)
|
|
|
|
excludeHeader(Mod, H);
|
|
|
|
else
|
|
|
|
addHeader(Mod, H, headerKindToRole(Header.Kind));
|
|
|
|
}
|
|
|
|
} else if (Header.HasBuiltinHeader && !Header.Size && !Header.ModTime) {
|
|
|
|
// There's a builtin header but no corresponding on-disk header. Assume
|
|
|
|
// this was supposed to modularize the builtin header alone.
|
|
|
|
} else if (Header.Kind == Module::HK_Excluded) {
|
|
|
|
// Ignore missing excluded header files. They're optional anyway.
|
|
|
|
} else {
|
|
|
|
// If we find a module that has a missing header, we mark this module as
|
|
|
|
// unavailable and store the header directive for displaying diagnostics.
|
|
|
|
Mod->MissingHeaders.push_back(Header);
|
|
|
|
// A missing header with stat information doesn't make the module
|
|
|
|
// unavailable; this keeps our behavior consistent as headers are lazily
|
|
|
|
// resolved. (Such a module still can't be built though, except from
|
|
|
|
// preprocessed source.)
|
|
|
|
if (!Header.Size && !Header.ModTime)
|
|
|
|
Mod->markUnavailable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ModuleMap::resolveAsBuiltinHeader(
|
|
|
|
Module *Mod, const Module::UnresolvedHeaderDirective &Header) {
|
|
|
|
if (Header.Kind == Module::HK_Excluded ||
|
|
|
|
llvm::sys::path::is_absolute(Header.FileName) ||
|
|
|
|
Mod->isPartOfFramework() || !Mod->IsSystem || Header.IsUmbrella ||
|
|
|
|
!BuiltinIncludeDir || BuiltinIncludeDir == Mod->Directory ||
|
|
|
|
!isBuiltinHeader(Header.FileName))
|
|
|
|
return false;
|
2017-05-26 08:01:53 +08:00
|
|
|
|
|
|
|
// This is a system module with a top-level header. This header
|
|
|
|
// may have a counterpart (or replacement) in the set of headers
|
|
|
|
// supplied by Clang. Find that builtin header.
|
2017-06-02 09:55:39 +08:00
|
|
|
SmallString<128> Path;
|
|
|
|
llvm::sys::path::append(Path, BuiltinIncludeDir->getName(), Header.FileName);
|
2019-08-02 05:31:56 +08:00
|
|
|
auto File = SourceMgr.getFileManager().getFile(Path);
|
2017-06-02 09:55:39 +08:00
|
|
|
if (!File)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
auto Role = headerKindToRole(Header.Kind);
|
2019-08-02 05:31:56 +08:00
|
|
|
Module::Header H = {Path.str(), *File};
|
2017-06-02 09:55:39 +08:00
|
|
|
addHeader(Mod, H, Role);
|
|
|
|
return true;
|
2017-05-26 08:01:53 +08:00
|
|
|
}
|
|
|
|
|
2013-12-17 18:31:37 +08:00
|
|
|
ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,
|
2013-03-14 05:13:51 +08:00
|
|
|
const LangOptions &LangOpts, const TargetInfo *Target,
|
|
|
|
HeaderSearch &HeaderInfo)
|
2013-12-17 18:31:37 +08:00
|
|
|
: SourceMgr(SourceMgr), Diags(Diags), LangOpts(LangOpts), Target(Target),
|
2017-09-06 05:46:22 +08:00
|
|
|
HeaderInfo(HeaderInfo) {
|
2015-02-14 13:32:00 +08:00
|
|
|
MMapLangOpts.LineComment = true;
|
|
|
|
}
|
2011-11-12 03:10:28 +08:00
|
|
|
|
|
|
|
ModuleMap::~ModuleMap() {
|
2016-03-09 07:58:08 +08:00
|
|
|
for (auto &M : Modules)
|
|
|
|
delete M.getValue();
|
2018-01-05 10:33:18 +08:00
|
|
|
for (auto *M : ShadowModules)
|
|
|
|
delete M;
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
2012-01-30 14:01:29 +08:00
|
|
|
void ModuleMap::setTarget(const TargetInfo &Target) {
|
2018-07-31 03:24:48 +08:00
|
|
|
assert((!this->Target || this->Target == &Target) &&
|
2012-01-30 14:01:29 +08:00
|
|
|
"Improper target override");
|
|
|
|
this->Target = &Target;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// "Sanitize" a filename so that it can be used as an identifier.
|
2012-10-13 05:15:50 +08:00
|
|
|
static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
|
|
|
|
SmallVectorImpl<char> &Buffer) {
|
|
|
|
if (Name.empty())
|
|
|
|
return Name;
|
|
|
|
|
2013-02-09 06:30:41 +08:00
|
|
|
if (!isValidIdentifier(Name)) {
|
2012-10-13 05:15:50 +08:00
|
|
|
// If we don't already have something with the form of an identifier,
|
|
|
|
// create a buffer with the sanitized name.
|
|
|
|
Buffer.clear();
|
2013-02-09 06:30:41 +08:00
|
|
|
if (isDigit(Name[0]))
|
2012-10-13 05:15:50 +08:00
|
|
|
Buffer.push_back('_');
|
|
|
|
Buffer.reserve(Buffer.size() + Name.size());
|
|
|
|
for (unsigned I = 0, N = Name.size(); I != N; ++I) {
|
2013-02-09 06:30:41 +08:00
|
|
|
if (isIdentifierBody(Name[I]))
|
2012-10-13 05:15:50 +08:00
|
|
|
Buffer.push_back(Name[I]);
|
|
|
|
else
|
|
|
|
Buffer.push_back('_');
|
|
|
|
}
|
|
|
|
|
|
|
|
Name = StringRef(Buffer.data(), Buffer.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
while (llvm::StringSwitch<bool>(Name)
|
|
|
|
#define KEYWORD(Keyword,Conditions) .Case(#Keyword, true)
|
|
|
|
#define ALIAS(Keyword, AliasOf, Conditions) .Case(Keyword, true)
|
|
|
|
#include "clang/Basic/TokenKinds.def"
|
|
|
|
.Default(false)) {
|
|
|
|
if (Name.data() != Buffer.data())
|
|
|
|
Buffer.append(Name.begin(), Name.end());
|
|
|
|
Buffer.push_back('_');
|
|
|
|
Name = StringRef(Buffer.data(), Buffer.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
return Name;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Determine whether the given file name is the name of a builtin
|
2013-05-03 01:58:30 +08:00
|
|
|
/// header, supplied by Clang to replace, override, or augment existing system
|
|
|
|
/// headers.
|
2017-01-11 10:14:51 +08:00
|
|
|
bool ModuleMap::isBuiltinHeader(StringRef FileName) {
|
2013-05-03 01:58:30 +08:00
|
|
|
return llvm::StringSwitch<bool>(FileName)
|
|
|
|
.Case("float.h", true)
|
|
|
|
.Case("iso646.h", true)
|
|
|
|
.Case("limits.h", true)
|
|
|
|
.Case("stdalign.h", true)
|
|
|
|
.Case("stdarg.h", true)
|
2016-03-10 07:31:34 +08:00
|
|
|
.Case("stdatomic.h", true)
|
2013-05-03 01:58:30 +08:00
|
|
|
.Case("stdbool.h", true)
|
|
|
|
.Case("stddef.h", true)
|
|
|
|
.Case("stdint.h", true)
|
|
|
|
.Case("tgmath.h", true)
|
|
|
|
.Case("unwind.h", true)
|
|
|
|
.Default(false);
|
|
|
|
}
|
|
|
|
|
2013-12-20 20:09:36 +08:00
|
|
|
ModuleMap::HeadersMap::iterator
|
|
|
|
ModuleMap::findKnownHeader(const FileEntry *File) {
|
2017-06-02 09:55:39 +08:00
|
|
|
resolveHeaderDirectives(File);
|
2012-10-15 14:28:11 +08:00
|
|
|
HeadersMap::iterator Known = Headers.find(File);
|
2015-06-16 08:08:24 +08:00
|
|
|
if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
|
|
|
|
Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
|
2017-01-11 10:14:51 +08:00
|
|
|
ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
|
2013-12-11 20:13:00 +08:00
|
|
|
HeaderInfo.loadTopLevelSystemModules();
|
2013-12-20 20:09:36 +08:00
|
|
|
return Headers.find(File);
|
2013-12-11 20:13:00 +08:00
|
|
|
}
|
2013-12-20 20:09:36 +08:00
|
|
|
return Known;
|
|
|
|
}
|
|
|
|
|
2014-04-10 08:39:10 +08:00
|
|
|
ModuleMap::KnownHeader
|
|
|
|
ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File,
|
|
|
|
SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs) {
|
2015-06-16 08:08:24 +08:00
|
|
|
if (UmbrellaDirs.empty())
|
2017-12-07 07:18:41 +08:00
|
|
|
return {};
|
2015-06-16 08:08:24 +08:00
|
|
|
|
2014-04-10 08:39:10 +08:00
|
|
|
const DirectoryEntry *Dir = File->getDir();
|
|
|
|
assert(Dir && "file in no directory");
|
|
|
|
|
|
|
|
// Note: as an egregious but useful hack we use the real path here, because
|
|
|
|
// frameworks moving from top-level frameworks to embedded frameworks tend
|
|
|
|
// to be symlinked from the top-level location to the embedded location,
|
|
|
|
// and we need to resolve lookups as if we had found the embedded location.
|
|
|
|
StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
|
|
|
|
|
|
|
|
// Keep walking up the directory hierarchy, looking for a directory with
|
|
|
|
// an umbrella header.
|
|
|
|
do {
|
|
|
|
auto KnownDir = UmbrellaDirs.find(Dir);
|
|
|
|
if (KnownDir != UmbrellaDirs.end())
|
|
|
|
return KnownHeader(KnownDir->second, NormalHeader);
|
|
|
|
|
|
|
|
IntermediateDirs.push_back(Dir);
|
|
|
|
|
|
|
|
// Retrieve our parent path.
|
|
|
|
DirName = llvm::sys::path::parent_path(DirName);
|
|
|
|
if (DirName.empty())
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Resolve the parent path to a directory entry.
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto DirEntry = SourceMgr.getFileManager().getDirectory(DirName))
|
|
|
|
Dir = *DirEntry;
|
|
|
|
else
|
|
|
|
Dir = nullptr;
|
2014-04-10 08:39:10 +08:00
|
|
|
} while (Dir);
|
2017-12-07 07:18:41 +08:00
|
|
|
return {};
|
2014-04-10 08:39:10 +08:00
|
|
|
}
|
|
|
|
|
2013-12-20 20:09:36 +08:00
|
|
|
static bool violatesPrivateInclude(Module *RequestingModule,
|
|
|
|
const FileEntry *IncFileEnt,
|
2016-04-28 05:57:05 +08:00
|
|
|
ModuleMap::KnownHeader Header) {
|
2014-10-25 04:23:01 +08:00
|
|
|
#ifndef NDEBUG
|
2016-04-28 05:57:05 +08:00
|
|
|
if (Header.getRole() & ModuleMap::PrivateHeader) {
|
2015-03-10 08:19:04 +08:00
|
|
|
// Check for consistency between the module header role
|
|
|
|
// as obtained from the lookup and as obtained from the module.
|
|
|
|
// This check is not cheap, so enable it only for debugging.
|
|
|
|
bool IsPrivate = false;
|
|
|
|
SmallVectorImpl<Module::Header> *HeaderList[] = {
|
2016-04-28 05:57:05 +08:00
|
|
|
&Header.getModule()->Headers[Module::HK_Private],
|
|
|
|
&Header.getModule()->Headers[Module::HK_PrivateTextual]};
|
2015-03-10 08:19:04 +08:00
|
|
|
for (auto *Hs : HeaderList)
|
|
|
|
IsPrivate |=
|
|
|
|
std::find_if(Hs->begin(), Hs->end(), [&](const Module::Header &H) {
|
2015-03-10 07:46:50 +08:00
|
|
|
return H.Entry == IncFileEnt;
|
2015-03-10 08:19:04 +08:00
|
|
|
}) != Hs->end();
|
2016-04-28 05:57:05 +08:00
|
|
|
assert(IsPrivate && "inconsistent headers and roles");
|
2015-03-10 08:19:04 +08:00
|
|
|
}
|
2014-10-25 04:23:01 +08:00
|
|
|
#endif
|
2016-04-28 05:57:05 +08:00
|
|
|
return !Header.isAccessibleFrom(RequestingModule);
|
2013-12-20 20:09:36 +08:00
|
|
|
}
|
|
|
|
|
2014-05-06 05:44:13 +08:00
|
|
|
static Module *getTopLevelOrNull(Module *M) {
|
|
|
|
return M ? M->getTopLevelModule() : nullptr;
|
|
|
|
}
|
|
|
|
|
2013-12-20 20:09:36 +08:00
|
|
|
void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
|
2016-03-15 01:52:37 +08:00
|
|
|
bool RequestingModuleIsModuleInterface,
|
2013-12-20 20:09:36 +08:00
|
|
|
SourceLocation FilenameLoc,
|
|
|
|
StringRef Filename,
|
|
|
|
const FileEntry *File) {
|
|
|
|
// No errors for indirect modules. This may be a bit of a problem for modules
|
|
|
|
// with no source files.
|
2014-05-06 05:44:13 +08:00
|
|
|
if (getTopLevelOrNull(RequestingModule) != getTopLevelOrNull(SourceModule))
|
2013-12-20 20:09:36 +08:00
|
|
|
return;
|
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
if (RequestingModule) {
|
2013-12-20 20:09:36 +08:00
|
|
|
resolveUses(RequestingModule, /*Complain=*/false);
|
2017-06-02 09:55:39 +08:00
|
|
|
resolveHeaderDirectives(RequestingModule);
|
|
|
|
}
|
2013-12-20 20:09:36 +08:00
|
|
|
|
2014-05-06 05:44:13 +08:00
|
|
|
bool Excluded = false;
|
2014-05-18 07:10:59 +08:00
|
|
|
Module *Private = nullptr;
|
|
|
|
Module *NotUsed = nullptr;
|
2013-12-20 20:09:36 +08:00
|
|
|
|
2014-05-06 05:44:13 +08:00
|
|
|
HeadersMap::iterator Known = findKnownHeader(File);
|
|
|
|
if (Known != Headers.end()) {
|
|
|
|
for (const KnownHeader &Header : Known->second) {
|
|
|
|
// Remember private headers for later printing of a diagnostic.
|
2016-04-28 05:57:05 +08:00
|
|
|
if (violatesPrivateInclude(RequestingModule, File, Header)) {
|
2014-05-06 05:44:13 +08:00
|
|
|
Private = Header.getModule();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If uses need to be specified explicitly, we are only allowed to return
|
|
|
|
// modules that are explicitly used by the requesting module.
|
|
|
|
if (RequestingModule && LangOpts.ModulesDeclUse &&
|
2015-03-27 06:10:01 +08:00
|
|
|
!RequestingModule->directlyUses(Header.getModule())) {
|
2014-05-06 05:44:13 +08:00
|
|
|
NotUsed = Header.getModule();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have found a module that we can happily use.
|
|
|
|
return;
|
2013-12-20 20:09:36 +08:00
|
|
|
}
|
2014-10-23 10:01:19 +08:00
|
|
|
|
|
|
|
Excluded = true;
|
2013-12-20 20:09:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We have found a header, but it is private.
|
2014-05-18 07:10:59 +08:00
|
|
|
if (Private) {
|
2015-02-19 08:10:28 +08:00
|
|
|
Diags.Report(FilenameLoc, diag::warn_use_of_private_header_outside_module)
|
2013-12-20 20:09:36 +08:00
|
|
|
<< Filename;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have found a module, but we don't use it.
|
2014-05-18 07:10:59 +08:00
|
|
|
if (NotUsed) {
|
2015-02-19 08:10:28 +08:00
|
|
|
Diags.Report(FilenameLoc, diag::err_undeclared_use_of_module)
|
2018-02-24 14:54:09 +08:00
|
|
|
<< RequestingModule->getTopLevelModule()->Name << Filename;
|
2013-12-20 20:09:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-06 05:44:13 +08:00
|
|
|
if (Excluded || isHeaderInUmbrellaDirs(File))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// At this point, only non-modular includes remain.
|
|
|
|
|
2018-11-05 20:46:02 +08:00
|
|
|
if (RequestingModule && LangOpts.ModulesStrictDeclUse) {
|
2015-02-19 08:10:28 +08:00
|
|
|
Diags.Report(FilenameLoc, diag::err_undeclared_use_of_module)
|
2018-02-24 14:54:09 +08:00
|
|
|
<< RequestingModule->getTopLevelModule()->Name << Filename;
|
2016-08-27 01:16:46 +08:00
|
|
|
} else if (RequestingModule && RequestingModuleIsModuleInterface &&
|
|
|
|
LangOpts.isCompilingModule()) {
|
2018-07-31 03:24:48 +08:00
|
|
|
// Do not diagnose when we are not compiling a module.
|
2014-05-06 05:44:13 +08:00
|
|
|
diag::kind DiagID = RequestingModule->getTopLevelModule()->IsFramework ?
|
|
|
|
diag::warn_non_modular_include_in_framework_module :
|
|
|
|
diag::warn_non_modular_include_in_module;
|
2016-10-22 07:27:37 +08:00
|
|
|
Diags.Report(FilenameLoc, DiagID) << RequestingModule->getFullModuleName()
|
|
|
|
<< File->getName();
|
2014-05-06 05:44:13 +08:00
|
|
|
}
|
2013-12-20 20:09:36 +08:00
|
|
|
}
|
|
|
|
|
2015-02-14 07:50:20 +08:00
|
|
|
static bool isBetterKnownHeader(const ModuleMap::KnownHeader &New,
|
|
|
|
const ModuleMap::KnownHeader &Old) {
|
[modules] PR20507: Avoid silent textual inclusion.
Summary:
If a module was unavailable (either a missing requirement on the module
being imported, or a missing file anywhere in the top-level module (and
not dominated by an unsatisfied `requires`)), we would silently treat
inclusions as textual. This would cause all manner of crazy and
confusing errors (and would also silently "work" sometimes, making the
problem difficult to track down).
I'm really not a fan of the `M->isAvailable(getLangOpts(), getTargetInfo(),
Requirement, MissingHeader)` function; it seems to do too many things at
once, but for now I've done things in a sort of awkward way.
The changes to test/Modules/Inputs/declare-use/module.map
were necessitated because the thing that was meant to be tested there
(introduced in r197805) was predicated on silently falling back to textual
inclusion, which we no longer do.
The changes to test/Modules/Inputs/macro-reexport/module.modulemap
are just an overlooked missing header that seems to have been missing since
this code was committed (r213922), which is now caught.
Reviewers: rsmith, benlangmuir, djasper
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D10423
llvm-svn: 245228
2015-08-18 00:39:30 +08:00
|
|
|
// Prefer available modules.
|
|
|
|
if (New.getModule()->isAvailable() && !Old.getModule()->isAvailable())
|
|
|
|
return true;
|
|
|
|
|
2015-02-14 07:50:20 +08:00
|
|
|
// Prefer a public header over a private header.
|
|
|
|
if ((New.getRole() & ModuleMap::PrivateHeader) !=
|
|
|
|
(Old.getRole() & ModuleMap::PrivateHeader))
|
|
|
|
return !(New.getRole() & ModuleMap::PrivateHeader);
|
|
|
|
|
|
|
|
// Prefer a non-textual header over a textual header.
|
|
|
|
if ((New.getRole() & ModuleMap::TextualHeader) !=
|
|
|
|
(Old.getRole() & ModuleMap::TextualHeader))
|
|
|
|
return !(New.getRole() & ModuleMap::TextualHeader);
|
|
|
|
|
|
|
|
// Don't have a reason to choose between these. Just keep the first one.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-10-21 09:41:56 +08:00
|
|
|
ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File,
|
|
|
|
bool AllowTextual) {
|
2014-10-23 07:50:56 +08:00
|
|
|
auto MakeResult = [&](ModuleMap::KnownHeader R) -> ModuleMap::KnownHeader {
|
2016-10-21 09:41:56 +08:00
|
|
|
if (!AllowTextual && R.getRole() & ModuleMap::TextualHeader)
|
2017-12-07 07:18:41 +08:00
|
|
|
return {};
|
2014-10-23 07:50:56 +08:00
|
|
|
return R;
|
|
|
|
};
|
|
|
|
|
2015-06-10 09:37:59 +08:00
|
|
|
HeadersMap::iterator Known = findKnownHeader(File);
|
2011-12-31 12:05:44 +08:00
|
|
|
if (Known != Headers.end()) {
|
2014-10-25 04:23:01 +08:00
|
|
|
ModuleMap::KnownHeader Result;
|
2013-10-22 16:09:47 +08:00
|
|
|
// Iterate over all modules that 'File' is part of to find the best fit.
|
2015-06-10 09:37:59 +08:00
|
|
|
for (KnownHeader &H : Known->second) {
|
2016-02-20 06:25:36 +08:00
|
|
|
// Prefer a header from the source module over all others.
|
|
|
|
if (H.getModule()->getTopLevelModule() == SourceModule)
|
2015-06-23 06:20:47 +08:00
|
|
|
return MakeResult(H);
|
2015-06-10 09:37:59 +08:00
|
|
|
if (!Result || isBetterKnownHeader(H, Result))
|
|
|
|
Result = H;
|
2013-10-22 16:09:47 +08:00
|
|
|
}
|
2014-10-23 07:50:56 +08:00
|
|
|
return MakeResult(Result);
|
2011-12-31 12:05:44 +08:00
|
|
|
}
|
2013-05-03 01:58:30 +08:00
|
|
|
|
2015-08-19 07:42:23 +08:00
|
|
|
return MakeResult(findOrCreateModuleForHeaderInUmbrellaDir(File));
|
|
|
|
}
|
|
|
|
|
|
|
|
ModuleMap::KnownHeader
|
|
|
|
ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) {
|
|
|
|
assert(!Headers.count(File) && "already have a module for this header");
|
|
|
|
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
|
2014-04-10 08:39:10 +08:00
|
|
|
KnownHeader H = findHeaderInUmbrellaDirs(File, SkippedDirs);
|
|
|
|
if (H) {
|
|
|
|
Module *Result = H.getModule();
|
|
|
|
|
|
|
|
// Search up the module stack until we find a module with an umbrella
|
|
|
|
// directory.
|
|
|
|
Module *UmbrellaModule = Result;
|
|
|
|
while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
|
|
|
|
UmbrellaModule = UmbrellaModule->Parent;
|
|
|
|
|
|
|
|
if (UmbrellaModule->InferSubmodules) {
|
2014-08-09 08:57:23 +08:00
|
|
|
const FileEntry *UmbrellaModuleMap =
|
|
|
|
getModuleMapFileForUniquing(UmbrellaModule);
|
|
|
|
|
2014-04-10 08:39:10 +08:00
|
|
|
// Infer submodules for each of the directories we found between
|
|
|
|
// the directory of the umbrella header and the directory where
|
|
|
|
// the actual header is located.
|
|
|
|
bool Explicit = UmbrellaModule->InferExplicitSubmodules;
|
|
|
|
|
|
|
|
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
|
|
|
|
// Find or create the module that corresponds to this directory name.
|
2012-10-13 05:15:50 +08:00
|
|
|
SmallString<32> NameBuf;
|
|
|
|
StringRef Name = sanitizeFilenameAsIdentifier(
|
2014-04-10 08:39:10 +08:00
|
|
|
llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf);
|
2014-08-09 08:57:23 +08:00
|
|
|
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
|
|
|
|
Explicit).first;
|
|
|
|
InferredModuleAllowedBy[Result] = UmbrellaModuleMap;
|
2014-04-24 05:10:46 +08:00
|
|
|
Result->IsInferred = true;
|
2014-04-10 08:39:10 +08:00
|
|
|
|
|
|
|
// Associate the module and the directory.
|
|
|
|
UmbrellaDirs[SkippedDirs[I-1]] = Result;
|
|
|
|
|
|
|
|
// If inferred submodules export everything they import, add a
|
2011-12-06 09:10:29 +08:00
|
|
|
// wildcard to the set of exports.
|
2011-12-07 00:17:15 +08:00
|
|
|
if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
|
2014-05-18 07:10:59 +08:00
|
|
|
Result->Exports.push_back(Module::ExportDecl(nullptr, true));
|
2011-12-06 09:10:29 +08:00
|
|
|
}
|
2011-12-31 12:05:44 +08:00
|
|
|
|
2014-04-10 08:39:10 +08:00
|
|
|
// Infer a submodule with the same name as this header file.
|
|
|
|
SmallString<32> NameBuf;
|
|
|
|
StringRef Name = sanitizeFilenameAsIdentifier(
|
2014-04-15 02:00:01 +08:00
|
|
|
llvm::sys::path::stem(File->getName()), NameBuf);
|
2014-08-09 08:57:23 +08:00
|
|
|
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
|
|
|
|
Explicit).first;
|
|
|
|
InferredModuleAllowedBy[Result] = UmbrellaModuleMap;
|
2014-04-24 05:10:46 +08:00
|
|
|
Result->IsInferred = true;
|
2014-04-10 08:39:10 +08:00
|
|
|
Result->addTopHeader(File);
|
|
|
|
|
|
|
|
// If inferred submodules export everything they import, add a
|
|
|
|
// wildcard to the set of exports.
|
|
|
|
if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
|
2014-05-18 07:10:59 +08:00
|
|
|
Result->Exports.push_back(Module::ExportDecl(nullptr, true));
|
2014-04-10 08:39:10 +08:00
|
|
|
} else {
|
|
|
|
// Record each of the directories we stepped through as being part of
|
|
|
|
// the module we found, since the umbrella header covers them all.
|
|
|
|
for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
|
|
|
|
UmbrellaDirs[SkippedDirs[I]] = Result;
|
2011-11-17 07:02:25 +08:00
|
|
|
}
|
2014-04-10 08:39:10 +08:00
|
|
|
|
2015-08-19 07:42:23 +08:00
|
|
|
KnownHeader Header(Result, NormalHeader);
|
|
|
|
Headers[File].push_back(Header);
|
|
|
|
return Header;
|
2014-04-10 08:39:10 +08:00
|
|
|
}
|
2014-10-23 07:50:56 +08:00
|
|
|
|
2017-12-07 07:18:41 +08:00
|
|
|
return {};
|
2011-11-12 06:18:48 +08:00
|
|
|
}
|
|
|
|
|
2015-08-19 07:42:23 +08:00
|
|
|
ArrayRef<ModuleMap::KnownHeader>
|
|
|
|
ModuleMap::findAllModulesForHeader(const FileEntry *File) const {
|
2017-06-02 09:55:39 +08:00
|
|
|
resolveHeaderDirectives(File);
|
2015-08-19 07:42:23 +08:00
|
|
|
auto It = Headers.find(File);
|
|
|
|
if (It == Headers.end())
|
|
|
|
return None;
|
|
|
|
return It->second;
|
|
|
|
}
|
|
|
|
|
2013-02-20 03:58:45 +08:00
|
|
|
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
|
2014-05-18 07:10:59 +08:00
|
|
|
return isHeaderUnavailableInModule(Header, nullptr);
|
2014-04-08 21:13:04 +08:00
|
|
|
}
|
|
|
|
|
2014-04-18 22:36:51 +08:00
|
|
|
bool
|
|
|
|
ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
|
|
|
|
const Module *RequestingModule) const {
|
2017-06-02 09:55:39 +08:00
|
|
|
resolveHeaderDirectives(Header);
|
2013-02-20 03:58:45 +08:00
|
|
|
HeadersMap::const_iterator Known = Headers.find(Header);
|
2013-10-22 16:09:47 +08:00
|
|
|
if (Known != Headers.end()) {
|
|
|
|
for (SmallVectorImpl<KnownHeader>::const_iterator
|
|
|
|
I = Known->second.begin(),
|
|
|
|
E = Known->second.end();
|
|
|
|
I != E; ++I) {
|
2017-01-13 03:15:33 +08:00
|
|
|
|
|
|
|
if (I->isAvailable() &&
|
|
|
|
(!RequestingModule ||
|
|
|
|
I->getModule()->isSubModuleOf(RequestingModule))) {
|
|
|
|
// When no requesting module is available, the caller is looking if a
|
|
|
|
// header is part a module by only looking into the module map. This is
|
|
|
|
// done by warn_uncovered_module_header checks; don't consider textual
|
|
|
|
// headers part of it in this mode, otherwise we get misleading warnings
|
|
|
|
// that a umbrella header is not including a textual header.
|
|
|
|
if (!RequestingModule && I->getRole() == ModuleMap::TextualHeader)
|
|
|
|
continue;
|
2013-10-22 16:09:47 +08:00
|
|
|
return false;
|
2017-01-13 03:15:33 +08:00
|
|
|
}
|
2013-10-22 16:09:47 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2014-04-08 21:13:04 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
const DirectoryEntry *Dir = Header->getDir();
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
|
2011-12-31 12:05:44 +08:00
|
|
|
StringRef DirName = Dir->getName();
|
|
|
|
|
2014-04-08 21:13:04 +08:00
|
|
|
auto IsUnavailable = [&](const Module *M) {
|
|
|
|
return !M->isAvailable() && (!RequestingModule ||
|
|
|
|
M->isSubModuleOf(RequestingModule));
|
|
|
|
};
|
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
// Keep walking up the directory hierarchy, looking for a directory with
|
|
|
|
// an umbrella header.
|
2014-04-08 21:13:04 +08:00
|
|
|
do {
|
2013-02-20 03:58:45 +08:00
|
|
|
llvm::DenseMap<const DirectoryEntry *, Module *>::const_iterator KnownDir
|
2011-12-31 12:05:44 +08:00
|
|
|
= UmbrellaDirs.find(Dir);
|
|
|
|
if (KnownDir != UmbrellaDirs.end()) {
|
|
|
|
Module *Found = KnownDir->second;
|
2014-04-08 21:13:04 +08:00
|
|
|
if (IsUnavailable(Found))
|
2011-12-31 12:05:44 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Search up the module stack until we find a module with an umbrella
|
|
|
|
// directory.
|
|
|
|
Module *UmbrellaModule = Found;
|
|
|
|
while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
|
|
|
|
UmbrellaModule = UmbrellaModule->Parent;
|
|
|
|
|
|
|
|
if (UmbrellaModule->InferSubmodules) {
|
|
|
|
for (unsigned I = SkippedDirs.size(); I != 0; --I) {
|
|
|
|
// Find or create the module that corresponds to this directory name.
|
2012-10-13 05:15:50 +08:00
|
|
|
SmallString<32> NameBuf;
|
|
|
|
StringRef Name = sanitizeFilenameAsIdentifier(
|
|
|
|
llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
|
|
|
|
NameBuf);
|
2011-12-31 12:05:44 +08:00
|
|
|
Found = lookupModuleQualified(Name, Found);
|
|
|
|
if (!Found)
|
|
|
|
return false;
|
2014-04-08 21:13:04 +08:00
|
|
|
if (IsUnavailable(Found))
|
2011-12-31 12:05:44 +08:00
|
|
|
return true;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
// Infer a submodule with the same name as this header file.
|
2012-10-13 05:15:50 +08:00
|
|
|
SmallString<32> NameBuf;
|
|
|
|
StringRef Name = sanitizeFilenameAsIdentifier(
|
|
|
|
llvm::sys::path::stem(Header->getName()),
|
|
|
|
NameBuf);
|
2011-12-31 12:05:44 +08:00
|
|
|
Found = lookupModuleQualified(Name, Found);
|
|
|
|
if (!Found)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-08 21:13:04 +08:00
|
|
|
return IsUnavailable(Found);
|
2011-12-31 12:05:44 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
SkippedDirs.push_back(Dir);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
// Retrieve our parent path.
|
|
|
|
DirName = llvm::sys::path::parent_path(DirName);
|
|
|
|
if (DirName.empty())
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
// Resolve the parent path to a directory entry.
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto DirEntry = SourceMgr.getFileManager().getDirectory(DirName))
|
|
|
|
Dir = *DirEntry;
|
|
|
|
else
|
|
|
|
Dir = nullptr;
|
2011-12-31 12:05:44 +08:00
|
|
|
} while (Dir);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-20 03:58:45 +08:00
|
|
|
Module *ModuleMap::findModule(StringRef Name) const {
|
|
|
|
llvm::StringMap<Module *>::const_iterator Known = Modules.find(Name);
|
2011-11-12 07:20:24 +08:00
|
|
|
if (Known != Modules.end())
|
|
|
|
return Known->getValue();
|
2014-05-18 07:10:59 +08:00
|
|
|
|
|
|
|
return nullptr;
|
2011-11-12 07:20:24 +08:00
|
|
|
}
|
|
|
|
|
2013-02-20 03:58:45 +08:00
|
|
|
Module *ModuleMap::lookupModuleUnqualified(StringRef Name,
|
|
|
|
Module *Context) const {
|
2011-12-02 09:47:07 +08:00
|
|
|
for(; Context; Context = Context->Parent) {
|
|
|
|
if (Module *Sub = lookupModuleQualified(Name, Context))
|
|
|
|
return Sub;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
return findModule(Name);
|
|
|
|
}
|
|
|
|
|
2013-02-20 03:58:45 +08:00
|
|
|
Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
|
2011-12-02 09:47:07 +08:00
|
|
|
if (!Context)
|
|
|
|
return findModule(Name);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-01-05 07:32:19 +08:00
|
|
|
return Context->findSubmodule(Name);
|
2011-12-02 09:47:07 +08:00
|
|
|
}
|
|
|
|
|
2018-01-06 06:13:56 +08:00
|
|
|
std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
|
|
|
|
Module *Parent,
|
|
|
|
bool IsFramework,
|
|
|
|
bool IsExplicit) {
|
2011-12-01 01:33:56 +08:00
|
|
|
// Try to find an existing module with this name.
|
2012-01-05 07:32:19 +08:00
|
|
|
if (Module *Sub = lookupModuleQualified(Name, Parent))
|
|
|
|
return std::make_pair(Sub, false);
|
2018-01-05 10:33:18 +08:00
|
|
|
|
2011-12-01 01:33:56 +08:00
|
|
|
// Create a new module with this name.
|
2017-01-30 13:00:26 +08:00
|
|
|
Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
|
|
|
|
IsExplicit, NumCreatedModules++);
|
2013-05-09 07:46:46 +08:00
|
|
|
if (!Parent) {
|
2016-02-20 06:25:36 +08:00
|
|
|
if (LangOpts.CurrentModule == Name)
|
|
|
|
SourceModule = Result;
|
2011-12-01 01:33:56 +08:00
|
|
|
Modules[Name] = Result;
|
2018-01-06 06:13:56 +08:00
|
|
|
ModuleScopeIDs[Result] = CurrentModuleScopeID;
|
2013-05-09 07:46:46 +08:00
|
|
|
}
|
2011-12-01 01:33:56 +08:00
|
|
|
return std::make_pair(Result, true);
|
|
|
|
}
|
|
|
|
|
2019-04-19 05:12:54 +08:00
|
|
|
Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc) {
|
2018-09-15 09:21:15 +08:00
|
|
|
PendingSubmodules.emplace_back(
|
2017-09-06 05:46:22 +08:00
|
|
|
new Module("<global>", Loc, nullptr, /*IsFramework*/ false,
|
|
|
|
/*IsExplicit*/ true, NumCreatedModules++));
|
2018-09-15 09:21:15 +08:00
|
|
|
PendingSubmodules.back()->Kind = Module::GlobalModuleFragment;
|
|
|
|
return PendingSubmodules.back().get();
|
2017-09-04 13:37:53 +08:00
|
|
|
}
|
|
|
|
|
2019-04-19 05:12:54 +08:00
|
|
|
Module *
|
|
|
|
ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent,
|
|
|
|
SourceLocation Loc) {
|
|
|
|
auto *Result =
|
|
|
|
new Module("<private>", Loc, Parent, /*IsFramework*/ false,
|
|
|
|
/*IsExplicit*/ true, NumCreatedModules++);
|
|
|
|
Result->Kind = Module::PrivateModuleFragment;
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2016-08-26 08:14:38 +08:00
|
|
|
Module *ModuleMap::createModuleForInterfaceUnit(SourceLocation Loc,
|
2017-09-04 13:37:53 +08:00
|
|
|
StringRef Name,
|
|
|
|
Module *GlobalModule) {
|
2016-08-26 08:14:38 +08:00
|
|
|
assert(LangOpts.CurrentModule == Name && "module name mismatch");
|
|
|
|
assert(!Modules[Name] && "redefining existing module");
|
|
|
|
|
|
|
|
auto *Result =
|
|
|
|
new Module(Name, Loc, nullptr, /*IsFramework*/ false,
|
|
|
|
/*IsExplicit*/ false, NumCreatedModules++);
|
2017-04-25 07:12:30 +08:00
|
|
|
Result->Kind = Module::ModuleInterfaceUnit;
|
2016-08-26 08:14:38 +08:00
|
|
|
Modules[Name] = SourceModule = Result;
|
|
|
|
|
2017-09-04 13:37:53 +08:00
|
|
|
// Reparent the current global module fragment as a submodule of this module.
|
2018-09-15 09:21:15 +08:00
|
|
|
for (auto &Submodule : PendingSubmodules) {
|
|
|
|
Submodule->setParent(Result);
|
|
|
|
Submodule.release(); // now owned by parent
|
|
|
|
}
|
|
|
|
PendingSubmodules.clear();
|
2017-09-04 13:37:53 +08:00
|
|
|
|
2016-08-26 08:14:38 +08:00
|
|
|
// Mark the main source file as being within the newly-created module so that
|
|
|
|
// declarations and macros are properly visibility-restricted to it.
|
|
|
|
auto *MainFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
|
|
|
|
assert(MainFile && "no input file for module interface");
|
|
|
|
Headers[MainFile].push_back(KnownHeader(Result, PrivateHeader));
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-09-15 09:21:15 +08:00
|
|
|
Module *ModuleMap::createHeaderModule(StringRef Name,
|
|
|
|
ArrayRef<Module::Header> Headers) {
|
|
|
|
assert(LangOpts.CurrentModule == Name && "module name mismatch");
|
|
|
|
assert(!Modules[Name] && "redefining existing module");
|
|
|
|
|
|
|
|
auto *Result =
|
|
|
|
new Module(Name, SourceLocation(), nullptr, /*IsFramework*/ false,
|
|
|
|
/*IsExplicit*/ false, NumCreatedModules++);
|
|
|
|
Result->Kind = Module::ModuleInterfaceUnit;
|
|
|
|
Modules[Name] = SourceModule = Result;
|
|
|
|
|
|
|
|
for (const Module::Header &H : Headers) {
|
|
|
|
auto *M = new Module(H.NameAsWritten, SourceLocation(), Result,
|
|
|
|
/*IsFramework*/ false,
|
|
|
|
/*IsExplicit*/ true, NumCreatedModules++);
|
|
|
|
// Header modules are implicitly 'export *'.
|
|
|
|
M->Exports.push_back(Module::ExportDecl(nullptr, true));
|
|
|
|
addHeader(M, H, NormalHeader);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// For a framework module, infer the framework against which we
|
2013-01-15 01:57:51 +08:00
|
|
|
/// should link.
|
|
|
|
static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir,
|
|
|
|
FileManager &FileMgr) {
|
|
|
|
assert(Mod->IsFramework && "Can only infer linking for framework modules");
|
|
|
|
assert(!Mod->isSubFramework() &&
|
|
|
|
"Can only infer linking for top-level frameworks");
|
|
|
|
|
|
|
|
SmallString<128> LibName;
|
|
|
|
LibName += FrameworkDir->getName();
|
|
|
|
llvm::sys::path::append(LibName, Mod->Name);
|
2015-11-14 03:08:07 +08:00
|
|
|
|
|
|
|
// The library name of a framework has more than one possible extension since
|
|
|
|
// the introduction of the text-based dynamic library format. We need to check
|
|
|
|
// for both before we give up.
|
2016-11-16 02:56:39 +08:00
|
|
|
for (const char *extension : {"", ".tbd"}) {
|
2015-11-14 03:08:07 +08:00
|
|
|
llvm::sys::path::replace_extension(LibName, extension);
|
|
|
|
if (FileMgr.getFile(LibName)) {
|
|
|
|
Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name,
|
|
|
|
/*IsFramework=*/true));
|
|
|
|
return;
|
|
|
|
}
|
2013-01-15 01:57:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-02 21:19:48 +08:00
|
|
|
Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
|
|
|
|
bool IsSystem, Module *Parent) {
|
2015-01-14 01:47:44 +08:00
|
|
|
Attributes Attrs;
|
|
|
|
Attrs.IsSystem = IsSystem;
|
2015-07-02 21:19:48 +08:00
|
|
|
return inferFrameworkModule(FrameworkDir, Attrs, Parent);
|
2015-01-14 01:47:44 +08:00
|
|
|
}
|
|
|
|
|
2015-07-02 21:19:48 +08:00
|
|
|
Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
|
2015-01-14 01:47:44 +08:00
|
|
|
Attributes Attrs, Module *Parent) {
|
2015-07-02 21:19:48 +08:00
|
|
|
// Note: as an egregious but useful hack we use the real path here, because
|
|
|
|
// we might be looking at an embedded framework that symlinks out to a
|
|
|
|
// top-level framework, and we need to infer as if we were naming the
|
|
|
|
// top-level framework.
|
|
|
|
StringRef FrameworkDirName =
|
|
|
|
SourceMgr.getFileManager().getCanonicalName(FrameworkDir);
|
|
|
|
|
|
|
|
// In case this is a case-insensitive filesystem, use the canonical
|
|
|
|
// directory name as the ModuleName, since modules are case-sensitive.
|
|
|
|
// FIXME: we should be able to give a fix-it hint for the correct spelling.
|
|
|
|
SmallString<32> ModuleNameStorage;
|
|
|
|
StringRef ModuleName = sanitizeFilenameAsIdentifier(
|
|
|
|
llvm::sys::path::stem(FrameworkDirName), ModuleNameStorage);
|
2015-01-14 01:47:44 +08:00
|
|
|
|
2011-11-17 09:41:17 +08:00
|
|
|
// Check whether we've already found this module.
|
2011-12-07 03:39:29 +08:00
|
|
|
if (Module *Mod = lookupModuleQualified(ModuleName, Parent))
|
|
|
|
return Mod;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
Use the same SourceManager for ModuleMaps and compilations.
This allows using virtual file mappings on the original SourceManager to
map in virtual module.map files. Without this patch, the ModuleMap
search will find a module.map file (as the FileEntry exists in the
FileManager), but will be unable to get the content from the
SourceManager (as ModuleMap previously created its own SourceManager).
Two problems needed to be fixed which this patch exposed:
1. Storing the inferred module map
When writing out a module, the ASTWriter stores the names of the files
in the main source manager; when loading the AST again, the ASTReader
errs out if such a file is found missing, unless it is overridden.
Previously CompilerInstance's compileModule method would store the
inferred module map to a temporary file; the problem with this approach
is that now that the module map is handled by the main source manager,
the ASTWriter stores the name of the temporary module map as source to
the compilation; later, when the module is loaded, the temporary file
has already been deleted, which leads to a compilation error. This patch
changes the inferred module map to instead inject a virtual file into
the source manager. This both saves some disk IO, and works with how the
ASTWriter/ASTReader handle overridden source files.
2. Changing test input in test/Modules/Inputs/*
Now that the module map file is handled by the main source manager, the
VerifyDiagnosticConsumer will not ignore diagnostics created while
parsing the module map file. The module test test/Modules/renamed.m uses
-I test/Modules/Inputs and triggers recursive loading of all module maps
in test/Modules/Inputs, some of which had conflicting names, thus
leading errors while parsing the module maps. Those diagnostics already
occur on trunk, but before this patch they would not break the test, as
they were ignored by the VerifyDiagnosticConsumer. This patch thus
changes the module maps that have been recently introduced which broke
the invariant of compatible modules maps in test/Modules/Inputs.
llvm-svn: 193314
2013-10-24 15:51:24 +08:00
|
|
|
FileManager &FileMgr = SourceMgr.getFileManager();
|
2012-11-07 03:39:40 +08:00
|
|
|
|
|
|
|
// If the framework has a parent path from which we're allowed to infer
|
|
|
|
// a framework module, do so.
|
2014-04-15 02:00:01 +08:00
|
|
|
const FileEntry *ModuleMapFile = nullptr;
|
2012-11-07 03:39:40 +08:00
|
|
|
if (!Parent) {
|
2013-01-10 09:43:00 +08:00
|
|
|
// Determine whether we're allowed to infer a module map.
|
2012-11-07 03:39:40 +08:00
|
|
|
bool canInfer = false;
|
2013-01-10 09:43:00 +08:00
|
|
|
if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
|
2012-11-07 03:39:40 +08:00
|
|
|
// Figure out the parent path.
|
2013-01-10 09:43:00 +08:00
|
|
|
StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName);
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto ParentDir = FileMgr.getDirectory(Parent)) {
|
2012-11-07 03:39:40 +08:00
|
|
|
// Check whether we have already looked into the parent directory
|
|
|
|
// for a module map.
|
2013-02-20 03:58:45 +08:00
|
|
|
llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
|
2019-08-02 05:31:56 +08:00
|
|
|
inferred = InferredDirectories.find(*ParentDir);
|
2012-11-07 03:39:40 +08:00
|
|
|
if (inferred == InferredDirectories.end()) {
|
|
|
|
// We haven't looked here before. Load a module map, if there is
|
|
|
|
// one.
|
2014-03-20 04:23:34 +08:00
|
|
|
bool IsFrameworkDir = Parent.endswith(".framework");
|
|
|
|
if (const FileEntry *ModMapFile =
|
2019-08-02 05:31:56 +08:00
|
|
|
HeaderInfo.lookupModuleMapFile(*ParentDir, IsFrameworkDir)) {
|
|
|
|
parseModuleMapFile(ModMapFile, Attrs.IsSystem, *ParentDir);
|
|
|
|
inferred = InferredDirectories.find(*ParentDir);
|
2012-11-07 03:39:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (inferred == InferredDirectories.end())
|
|
|
|
inferred = InferredDirectories.insert(
|
2019-08-02 05:31:56 +08:00
|
|
|
std::make_pair(*ParentDir, InferredDirectory())).first;
|
2012-11-07 03:39:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (inferred->second.InferModules) {
|
|
|
|
// We're allowed to infer for this directory, but make sure it's okay
|
|
|
|
// to infer this particular module.
|
2013-01-10 09:43:00 +08:00
|
|
|
StringRef Name = llvm::sys::path::stem(FrameworkDirName);
|
2012-11-07 03:39:40 +08:00
|
|
|
canInfer = std::find(inferred->second.ExcludedModules.begin(),
|
|
|
|
inferred->second.ExcludedModules.end(),
|
|
|
|
Name) == inferred->second.ExcludedModules.end();
|
|
|
|
|
2015-01-14 01:47:44 +08:00
|
|
|
Attrs.IsSystem |= inferred->second.Attrs.IsSystem;
|
|
|
|
Attrs.IsExternC |= inferred->second.Attrs.IsExternC;
|
|
|
|
Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive;
|
2016-10-21 09:41:56 +08:00
|
|
|
Attrs.NoUndeclaredIncludes |=
|
|
|
|
inferred->second.Attrs.NoUndeclaredIncludes;
|
2014-04-15 02:00:01 +08:00
|
|
|
ModuleMapFile = inferred->second.ModuleMapFile;
|
2012-11-07 03:39:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're not allowed to infer a framework module, don't.
|
|
|
|
if (!canInfer)
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2014-04-15 02:00:01 +08:00
|
|
|
} else
|
2014-08-09 08:57:23 +08:00
|
|
|
ModuleMapFile = getModuleMapFileForUniquing(Parent);
|
2012-11-07 03:39:40 +08:00
|
|
|
|
|
|
|
|
2011-11-17 09:41:17 +08:00
|
|
|
// Look for an umbrella header.
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
|
2013-06-29 00:25:46 +08:00
|
|
|
llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h");
|
2019-08-02 05:31:56 +08:00
|
|
|
auto UmbrellaHeader = FileMgr.getFile(UmbrellaName);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-17 09:41:17 +08:00
|
|
|
// FIXME: If there's no umbrella header, we could probably scan the
|
|
|
|
// framework to load *everything*. But, it's not clear that this is a good
|
|
|
|
// idea.
|
|
|
|
if (!UmbrellaHeader)
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2014-08-09 08:57:23 +08:00
|
|
|
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
|
2015-05-01 09:53:09 +08:00
|
|
|
/*IsFramework=*/true, /*IsExplicit=*/false,
|
|
|
|
NumCreatedModules++);
|
2014-08-09 08:57:23 +08:00
|
|
|
InferredModuleAllowedBy[Result] = ModuleMapFile;
|
|
|
|
Result->IsInferred = true;
|
2016-02-20 06:25:36 +08:00
|
|
|
if (!Parent) {
|
|
|
|
if (LangOpts.CurrentModule == ModuleName)
|
|
|
|
SourceModule = Result;
|
|
|
|
Modules[ModuleName] = Result;
|
2018-01-06 06:13:56 +08:00
|
|
|
ModuleScopeIDs[Result] = CurrentModuleScopeID;
|
2013-09-24 17:14:14 +08:00
|
|
|
}
|
2015-01-14 01:47:44 +08:00
|
|
|
|
|
|
|
Result->IsSystem |= Attrs.IsSystem;
|
|
|
|
Result->IsExternC |= Attrs.IsExternC;
|
|
|
|
Result->ConfigMacrosExhaustive |= Attrs.IsExhaustive;
|
2016-10-21 09:41:56 +08:00
|
|
|
Result->NoUndeclaredIncludes |= Attrs.NoUndeclaredIncludes;
|
2015-05-16 10:28:53 +08:00
|
|
|
Result->Directory = FrameworkDir;
|
2015-01-14 01:47:44 +08:00
|
|
|
|
2011-12-09 02:00:48 +08:00
|
|
|
// umbrella header "umbrella-header-name"
|
2015-05-16 10:28:53 +08:00
|
|
|
//
|
|
|
|
// The "Headers/" component of the name is implied because this is
|
|
|
|
// a framework module.
|
2019-08-02 05:31:56 +08:00
|
|
|
setUmbrellaHeader(Result, *UmbrellaHeader, ModuleName + ".h");
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-06 01:40:25 +08:00
|
|
|
// export *
|
2014-05-18 07:10:59 +08:00
|
|
|
Result->Exports.push_back(Module::ExportDecl(nullptr, true));
|
|
|
|
|
2011-12-06 09:10:29 +08:00
|
|
|
// module * { export * }
|
|
|
|
Result->InferSubmodules = true;
|
|
|
|
Result->InferExportWildcard = true;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 03:39:29 +08:00
|
|
|
// Look for subframeworks.
|
2014-06-12 22:02:15 +08:00
|
|
|
std::error_code EC;
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> SubframeworksDirName
|
2011-12-09 00:13:24 +08:00
|
|
|
= StringRef(FrameworkDir->getName());
|
2011-12-07 03:39:29 +08:00
|
|
|
llvm::sys::path::append(SubframeworksDirName, "Frameworks");
|
2013-09-11 19:23:15 +08:00
|
|
|
llvm::sys::path::native(SubframeworksDirName);
|
2019-03-27 06:32:06 +08:00
|
|
|
llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
|
2018-10-10 21:27:25 +08:00
|
|
|
for (llvm::vfs::directory_iterator
|
|
|
|
Dir = FS.dir_begin(SubframeworksDirName, EC),
|
|
|
|
DirEnd;
|
2011-12-07 03:39:29 +08:00
|
|
|
Dir != DirEnd && !EC; Dir.increment(EC)) {
|
2018-09-14 20:47:38 +08:00
|
|
|
if (!StringRef(Dir->path()).endswith(".framework"))
|
2011-12-07 03:39:29 +08:00
|
|
|
continue;
|
2012-09-27 22:50:15 +08:00
|
|
|
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto SubframeworkDir =
|
2018-09-14 20:47:38 +08:00
|
|
|
FileMgr.getDirectory(Dir->path())) {
|
2012-09-27 22:50:15 +08:00
|
|
|
// Note: as an egregious but useful hack, we use the real path here and
|
|
|
|
// check whether it is actually a subdirectory of the parent directory.
|
|
|
|
// This will not be the case if the 'subframework' is actually a symlink
|
|
|
|
// out to a top-level framework.
|
2019-08-02 05:31:56 +08:00
|
|
|
StringRef SubframeworkDirName =
|
|
|
|
FileMgr.getCanonicalName(*SubframeworkDir);
|
2013-01-26 08:55:12 +08:00
|
|
|
bool FoundParent = false;
|
|
|
|
do {
|
|
|
|
// Get the parent directory name.
|
|
|
|
SubframeworkDirName
|
|
|
|
= llvm::sys::path::parent_path(SubframeworkDirName);
|
|
|
|
if (SubframeworkDirName.empty())
|
|
|
|
break;
|
|
|
|
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto SubDir = FileMgr.getDirectory(SubframeworkDirName)) {
|
|
|
|
if (*SubDir == FrameworkDir) {
|
|
|
|
FoundParent = true;
|
|
|
|
break;
|
|
|
|
}
|
2013-01-26 08:55:12 +08:00
|
|
|
}
|
|
|
|
} while (true);
|
2012-09-27 22:50:15 +08:00
|
|
|
|
2013-01-26 08:55:12 +08:00
|
|
|
if (!FoundParent)
|
|
|
|
continue;
|
2012-09-27 22:50:15 +08:00
|
|
|
|
2011-12-07 03:39:29 +08:00
|
|
|
// FIXME: Do we want to warn about subframeworks without umbrella headers?
|
2019-08-02 05:31:56 +08:00
|
|
|
inferFrameworkModule(*SubframeworkDir, Attrs, Result);
|
2011-12-07 03:39:29 +08:00
|
|
|
}
|
|
|
|
}
|
2012-01-14 00:54:27 +08:00
|
|
|
|
2013-01-15 01:57:51 +08:00
|
|
|
// If the module is a top-level framework, automatically link against the
|
|
|
|
// framework.
|
|
|
|
if (!Result->isSubFramework()) {
|
|
|
|
inferFrameworkLink(Result, FrameworkDir, FileMgr);
|
|
|
|
}
|
|
|
|
|
2011-11-17 09:41:17 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-01-05 10:33:18 +08:00
|
|
|
Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,
|
|
|
|
Module *ShadowingModule) {
|
|
|
|
|
|
|
|
// Create a new module with this name.
|
|
|
|
Module *Result =
|
|
|
|
new Module(Name, SourceLocation(), /*Parent=*/nullptr, IsFramework,
|
|
|
|
/*IsExplicit=*/false, NumCreatedModules++);
|
|
|
|
Result->ShadowingModule = ShadowingModule;
|
|
|
|
Result->IsAvailable = false;
|
2018-01-06 06:13:56 +08:00
|
|
|
ModuleScopeIDs[Result] = CurrentModuleScopeID;
|
2018-01-05 10:33:18 +08:00
|
|
|
ShadowModules.push_back(Result);
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2015-05-16 10:28:53 +08:00
|
|
|
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader,
|
|
|
|
Twine NameAsWritten) {
|
2013-10-22 16:09:47 +08:00
|
|
|
Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
|
2011-12-09 01:39:04 +08:00
|
|
|
Mod->Umbrella = UmbrellaHeader;
|
2015-05-16 10:28:53 +08:00
|
|
|
Mod->UmbrellaAsWritten = NameAsWritten.str();
|
2011-12-09 10:04:43 +08:00
|
|
|
UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
|
2016-05-14 06:21:51 +08:00
|
|
|
|
|
|
|
// Notify callbacks that we just added a new header.
|
|
|
|
for (const auto &Cb : Callbacks)
|
|
|
|
Cb->moduleMapAddUmbrellaHeader(&SourceMgr.getFileManager(), UmbrellaHeader);
|
2011-12-06 09:10:29 +08:00
|
|
|
}
|
|
|
|
|
2015-05-16 10:28:53 +08:00
|
|
|
void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir,
|
|
|
|
Twine NameAsWritten) {
|
2011-12-09 03:11:24 +08:00
|
|
|
Mod->Umbrella = UmbrellaDir;
|
2015-05-16 10:28:53 +08:00
|
|
|
Mod->UmbrellaAsWritten = NameAsWritten.str();
|
2011-12-09 03:11:24 +08:00
|
|
|
UmbrellaDirs[UmbrellaDir] = Mod;
|
|
|
|
}
|
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
void ModuleMap::addUnresolvedHeader(Module *Mod,
|
2018-06-01 09:26:18 +08:00
|
|
|
Module::UnresolvedHeaderDirective Header,
|
|
|
|
bool &NeedsFramework) {
|
2017-06-02 09:55:39 +08:00
|
|
|
// If there is a builtin counterpart to this file, add it now so it can
|
|
|
|
// wrap the system header.
|
|
|
|
if (resolveAsBuiltinHeader(Mod, Header)) {
|
|
|
|
// If we have both a builtin and system version of the file, the
|
|
|
|
// builtin version may want to inject macros into the system header, so
|
|
|
|
// force the system header to be treated as a textual header in this
|
|
|
|
// case.
|
|
|
|
Header.Kind = headerRoleToKind(ModuleMap::ModuleHeaderRole(
|
|
|
|
headerKindToRole(Header.Kind) | ModuleMap::TextualHeader));
|
|
|
|
Header.HasBuiltinHeader = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If possible, don't stat the header until we need to. This requires the
|
|
|
|
// user to have provided us with some stat information about the file.
|
|
|
|
// FIXME: Add support for lazily stat'ing umbrella headers and excluded
|
|
|
|
// headers.
|
|
|
|
if ((Header.Size || Header.ModTime) && !Header.IsUmbrella &&
|
|
|
|
Header.Kind != Module::HK_Excluded) {
|
|
|
|
// We expect more variation in mtime than size, so if we're given both,
|
|
|
|
// use the mtime as the key.
|
|
|
|
if (Header.ModTime)
|
|
|
|
LazyHeadersByModTime[*Header.ModTime].push_back(Mod);
|
|
|
|
else
|
|
|
|
LazyHeadersBySize[*Header.Size].push_back(Mod);
|
|
|
|
Mod->UnresolvedHeaders.push_back(Header);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't have stat information or can't defer looking this file up.
|
|
|
|
// Perform the lookup now.
|
2018-06-01 09:26:18 +08:00
|
|
|
resolveHeader(Mod, Header, NeedsFramework);
|
2017-06-02 09:55:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleMap::resolveHeaderDirectives(const FileEntry *File) const {
|
|
|
|
auto BySize = LazyHeadersBySize.find(File->getSize());
|
|
|
|
if (BySize != LazyHeadersBySize.end()) {
|
|
|
|
for (auto *M : BySize->second)
|
|
|
|
resolveHeaderDirectives(M);
|
|
|
|
LazyHeadersBySize.erase(BySize);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ByModTime = LazyHeadersByModTime.find(File->getModificationTime());
|
|
|
|
if (ByModTime != LazyHeadersByModTime.end()) {
|
|
|
|
for (auto *M : ByModTime->second)
|
|
|
|
resolveHeaderDirectives(M);
|
|
|
|
LazyHeadersByModTime.erase(ByModTime);
|
2014-10-26 21:12:35 +08:00
|
|
|
}
|
2014-12-02 08:08:08 +08:00
|
|
|
}
|
2014-10-25 04:23:01 +08:00
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
void ModuleMap::resolveHeaderDirectives(Module *Mod) const {
|
2018-06-01 09:26:18 +08:00
|
|
|
bool NeedsFramework = false;
|
2017-06-02 09:55:39 +08:00
|
|
|
for (auto &Header : Mod->UnresolvedHeaders)
|
|
|
|
// This operation is logically const; we're just changing how we represent
|
|
|
|
// the header information for this file.
|
2018-06-01 09:26:18 +08:00
|
|
|
const_cast<ModuleMap*>(this)->resolveHeader(Mod, Header, NeedsFramework);
|
2017-06-02 09:55:39 +08:00
|
|
|
Mod->UnresolvedHeaders.clear();
|
|
|
|
}
|
|
|
|
|
2014-12-02 08:08:08 +08:00
|
|
|
void ModuleMap::addHeader(Module *Mod, Module::Header Header,
|
2015-08-25 05:59:32 +08:00
|
|
|
ModuleHeaderRole Role, bool Imported) {
|
2015-08-19 07:42:23 +08:00
|
|
|
KnownHeader KH(Mod, Role);
|
|
|
|
|
|
|
|
// Only add each header to the headers list once.
|
|
|
|
// FIXME: Should we diagnose if a header is listed twice in the
|
|
|
|
// same module definition?
|
|
|
|
auto &HeaderList = Headers[Header.Entry];
|
|
|
|
for (auto H : HeaderList)
|
|
|
|
if (H == KH)
|
|
|
|
return;
|
2011-12-06 09:10:29 +08:00
|
|
|
|
2015-08-19 07:42:23 +08:00
|
|
|
HeaderList.push_back(KH);
|
2016-12-23 19:40:44 +08:00
|
|
|
Mod->Headers[headerRoleToKind(Role)].push_back(Header);
|
2015-08-19 07:42:23 +08:00
|
|
|
|
2016-02-20 06:25:36 +08:00
|
|
|
bool isCompilingModuleHeader =
|
2016-08-26 08:14:38 +08:00
|
|
|
LangOpts.isCompilingModule() && Mod->getTopLevelModule() == SourceModule;
|
2015-08-25 05:59:32 +08:00
|
|
|
if (!Imported || isCompilingModuleHeader) {
|
|
|
|
// When we import HeaderFileInfo, the external source is expected to
|
|
|
|
// set the isModuleHeader flag itself.
|
|
|
|
HeaderInfo.MarkFileModuleHeader(Header.Entry, Role,
|
|
|
|
isCompilingModuleHeader);
|
|
|
|
}
|
2016-03-31 07:54:25 +08:00
|
|
|
|
|
|
|
// Notify callbacks that we just added a new header.
|
|
|
|
for (const auto &Cb : Callbacks)
|
2016-05-07 07:21:50 +08:00
|
|
|
Cb->moduleMapAddHeader(Header.Entry->getName());
|
2014-12-02 08:08:08 +08:00
|
|
|
}
|
2014-10-23 10:01:19 +08:00
|
|
|
|
2014-12-02 08:08:08 +08:00
|
|
|
void ModuleMap::excludeHeader(Module *Mod, Module::Header Header) {
|
2014-10-23 10:01:19 +08:00
|
|
|
// Add this as a known header so we won't implicitly add it to any
|
|
|
|
// umbrella directory module.
|
|
|
|
// FIXME: Should we only exclude it from umbrella modules within the
|
|
|
|
// specified module?
|
2014-12-02 08:08:08 +08:00
|
|
|
(void) Headers[Header.Entry];
|
|
|
|
|
|
|
|
Mod->Headers[Module::HK_Excluded].push_back(std::move(Header));
|
2014-10-23 10:01:19 +08:00
|
|
|
}
|
|
|
|
|
2011-11-30 03:06:37 +08:00
|
|
|
const FileEntry *
|
2014-08-13 00:42:33 +08:00
|
|
|
ModuleMap::getContainingModuleMapFile(const Module *Module) const {
|
Use the same SourceManager for ModuleMaps and compilations.
This allows using virtual file mappings on the original SourceManager to
map in virtual module.map files. Without this patch, the ModuleMap
search will find a module.map file (as the FileEntry exists in the
FileManager), but will be unable to get the content from the
SourceManager (as ModuleMap previously created its own SourceManager).
Two problems needed to be fixed which this patch exposed:
1. Storing the inferred module map
When writing out a module, the ASTWriter stores the names of the files
in the main source manager; when loading the AST again, the ASTReader
errs out if such a file is found missing, unless it is overridden.
Previously CompilerInstance's compileModule method would store the
inferred module map to a temporary file; the problem with this approach
is that now that the module map is handled by the main source manager,
the ASTWriter stores the name of the temporary module map as source to
the compilation; later, when the module is loaded, the temporary file
has already been deleted, which leads to a compilation error. This patch
changes the inferred module map to instead inject a virtual file into
the source manager. This both saves some disk IO, and works with how the
ASTWriter/ASTReader handle overridden source files.
2. Changing test input in test/Modules/Inputs/*
Now that the module map file is handled by the main source manager, the
VerifyDiagnosticConsumer will not ignore diagnostics created while
parsing the module map file. The module test test/Modules/renamed.m uses
-I test/Modules/Inputs and triggers recursive loading of all module maps
in test/Modules/Inputs, some of which had conflicting names, thus
leading errors while parsing the module maps. Those diagnostics already
occur on trunk, but before this patch they would not break the test, as
they were ignored by the VerifyDiagnosticConsumer. This patch thus
changes the module maps that have been recently introduced which broke
the invariant of compatible modules maps in test/Modules/Inputs.
llvm-svn: 193314
2013-10-24 15:51:24 +08:00
|
|
|
if (Module->DefinitionLoc.isInvalid())
|
2014-05-18 07:10:59 +08:00
|
|
|
return nullptr;
|
2011-11-30 03:06:37 +08:00
|
|
|
|
Use the same SourceManager for ModuleMaps and compilations.
This allows using virtual file mappings on the original SourceManager to
map in virtual module.map files. Without this patch, the ModuleMap
search will find a module.map file (as the FileEntry exists in the
FileManager), but will be unable to get the content from the
SourceManager (as ModuleMap previously created its own SourceManager).
Two problems needed to be fixed which this patch exposed:
1. Storing the inferred module map
When writing out a module, the ASTWriter stores the names of the files
in the main source manager; when loading the AST again, the ASTReader
errs out if such a file is found missing, unless it is overridden.
Previously CompilerInstance's compileModule method would store the
inferred module map to a temporary file; the problem with this approach
is that now that the module map is handled by the main source manager,
the ASTWriter stores the name of the temporary module map as source to
the compilation; later, when the module is loaded, the temporary file
has already been deleted, which leads to a compilation error. This patch
changes the inferred module map to instead inject a virtual file into
the source manager. This both saves some disk IO, and works with how the
ASTWriter/ASTReader handle overridden source files.
2. Changing test input in test/Modules/Inputs/*
Now that the module map file is handled by the main source manager, the
VerifyDiagnosticConsumer will not ignore diagnostics created while
parsing the module map file. The module test test/Modules/renamed.m uses
-I test/Modules/Inputs and triggers recursive loading of all module maps
in test/Modules/Inputs, some of which had conflicting names, thus
leading errors while parsing the module maps. Those diagnostics already
occur on trunk, but before this patch they would not break the test, as
they were ignored by the VerifyDiagnosticConsumer. This patch thus
changes the module maps that have been recently introduced which broke
the invariant of compatible modules maps in test/Modules/Inputs.
llvm-svn: 193314
2013-10-24 15:51:24 +08:00
|
|
|
return SourceMgr.getFileEntryForID(
|
|
|
|
SourceMgr.getFileID(Module->DefinitionLoc));
|
2011-11-30 03:06:37 +08:00
|
|
|
}
|
|
|
|
|
2014-08-13 00:42:33 +08:00
|
|
|
const FileEntry *ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
|
2014-08-09 08:57:23 +08:00
|
|
|
if (M->IsInferred) {
|
|
|
|
assert(InferredModuleAllowedBy.count(M) && "missing inferred module map");
|
|
|
|
return InferredModuleAllowedBy.find(M)->second;
|
|
|
|
}
|
|
|
|
return getContainingModuleMapFile(M);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleMap::setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap) {
|
|
|
|
assert(M->IsInferred && "module not inferred");
|
|
|
|
InferredModuleAllowedBy[M] = ModMap;
|
|
|
|
}
|
|
|
|
|
2016-01-30 03:38:18 +08:00
|
|
|
LLVM_DUMP_METHOD void ModuleMap::dump() {
|
2011-11-12 03:10:28 +08:00
|
|
|
llvm::errs() << "Modules:";
|
2018-07-31 03:24:48 +08:00
|
|
|
for (llvm::StringMap<Module *>::iterator M = Modules.begin(),
|
|
|
|
MEnd = Modules.end();
|
2011-11-12 03:10:28 +08:00
|
|
|
M != MEnd; ++M)
|
2011-11-30 02:17:59 +08:00
|
|
|
M->getValue()->print(llvm::errs(), 2);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
llvm::errs() << "Headers:";
|
2012-10-15 14:28:11 +08:00
|
|
|
for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end();
|
2011-11-12 03:10:28 +08:00
|
|
|
H != HEnd; ++H) {
|
2013-10-22 16:09:47 +08:00
|
|
|
llvm::errs() << " \"" << H->first->getName() << "\" -> ";
|
|
|
|
for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(),
|
|
|
|
E = H->second.end();
|
|
|
|
I != E; ++I) {
|
|
|
|
if (I != H->second.begin())
|
|
|
|
llvm::errs() << ",";
|
|
|
|
llvm::errs() << I->getModule()->getFullModuleName();
|
|
|
|
}
|
|
|
|
llvm::errs() << "\n";
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
|
2015-05-16 04:05:43 +08:00
|
|
|
auto Unresolved = std::move(Mod->UnresolvedExports);
|
|
|
|
Mod->UnresolvedExports.clear();
|
|
|
|
for (auto &UE : Unresolved) {
|
|
|
|
Module::ExportDecl Export = resolveExport(Mod, UE, Complain);
|
2011-12-06 01:28:06 +08:00
|
|
|
if (Export.getPointer() || Export.getInt())
|
2011-12-02 09:47:07 +08:00
|
|
|
Mod->Exports.push_back(Export);
|
|
|
|
else
|
2015-05-16 04:05:43 +08:00
|
|
|
Mod->UnresolvedExports.push_back(UE);
|
2011-12-02 09:47:07 +08:00
|
|
|
}
|
2015-05-16 04:05:43 +08:00
|
|
|
return !Mod->UnresolvedExports.empty();
|
2011-12-02 09:47:07 +08:00
|
|
|
}
|
|
|
|
|
2013-09-24 17:14:14 +08:00
|
|
|
bool ModuleMap::resolveUses(Module *Mod, bool Complain) {
|
2015-05-16 04:05:43 +08:00
|
|
|
auto Unresolved = std::move(Mod->UnresolvedDirectUses);
|
|
|
|
Mod->UnresolvedDirectUses.clear();
|
|
|
|
for (auto &UDU : Unresolved) {
|
|
|
|
Module *DirectUse = resolveModuleId(UDU, Mod, Complain);
|
2013-09-24 17:14:14 +08:00
|
|
|
if (DirectUse)
|
|
|
|
Mod->DirectUses.push_back(DirectUse);
|
|
|
|
else
|
2015-05-16 04:05:43 +08:00
|
|
|
Mod->UnresolvedDirectUses.push_back(UDU);
|
2013-09-24 17:14:14 +08:00
|
|
|
}
|
2015-05-16 04:05:43 +08:00
|
|
|
return !Mod->UnresolvedDirectUses.empty();
|
2013-09-24 17:14:14 +08:00
|
|
|
}
|
|
|
|
|
2013-03-21 05:10:35 +08:00
|
|
|
bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
|
2015-05-16 04:05:43 +08:00
|
|
|
auto Unresolved = std::move(Mod->UnresolvedConflicts);
|
2013-03-21 05:10:35 +08:00
|
|
|
Mod->UnresolvedConflicts.clear();
|
2015-05-16 04:05:43 +08:00
|
|
|
for (auto &UC : Unresolved) {
|
|
|
|
if (Module *OtherMod = resolveModuleId(UC.Id, Mod, Complain)) {
|
|
|
|
Module::Conflict Conflict;
|
|
|
|
Conflict.Other = OtherMod;
|
|
|
|
Conflict.Message = UC.Message;
|
|
|
|
Mod->Conflicts.push_back(Conflict);
|
|
|
|
} else
|
|
|
|
Mod->UnresolvedConflicts.push_back(UC);
|
|
|
|
}
|
|
|
|
return !Mod->UnresolvedConflicts.empty();
|
2013-03-21 05:10:35 +08:00
|
|
|
}
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
// Module map file parser
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
|
|
namespace clang {
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// A token in a module map file.
|
2011-11-12 03:10:28 +08:00
|
|
|
struct MMToken {
|
|
|
|
enum TokenKind {
|
2011-12-31 12:05:44 +08:00
|
|
|
Comma,
|
2013-03-20 08:22:05 +08:00
|
|
|
ConfigMacros,
|
2013-03-21 05:10:35 +08:00
|
|
|
Conflict,
|
2011-11-12 03:10:28 +08:00
|
|
|
EndOfFile,
|
|
|
|
HeaderKeyword,
|
|
|
|
Identifier,
|
2013-10-29 06:18:19 +08:00
|
|
|
Exclaim,
|
2012-10-15 14:28:11 +08:00
|
|
|
ExcludeKeyword,
|
2011-11-12 03:10:28 +08:00
|
|
|
ExplicitKeyword,
|
2011-12-02 09:47:07 +08:00
|
|
|
ExportKeyword,
|
2017-09-15 07:38:44 +08:00
|
|
|
ExportAsKeyword,
|
2013-09-11 15:20:44 +08:00
|
|
|
ExternKeyword,
|
2011-11-18 06:09:43 +08:00
|
|
|
FrameworkKeyword,
|
2013-01-15 01:21:00 +08:00
|
|
|
LinkKeyword,
|
2011-11-12 03:10:28 +08:00
|
|
|
ModuleKeyword,
|
2011-12-02 09:47:07 +08:00
|
|
|
Period,
|
2013-06-21 05:14:14 +08:00
|
|
|
PrivateKeyword,
|
2011-11-12 03:10:28 +08:00
|
|
|
UmbrellaKeyword,
|
2013-09-24 17:14:14 +08:00
|
|
|
UseKeyword,
|
2011-12-31 12:05:44 +08:00
|
|
|
RequiresKeyword,
|
2011-12-02 09:47:07 +08:00
|
|
|
Star,
|
2011-11-12 03:10:28 +08:00
|
|
|
StringLiteral,
|
2017-06-02 09:55:39 +08:00
|
|
|
IntegerLiteral,
|
2014-10-23 07:50:56 +08:00
|
|
|
TextualKeyword,
|
2011-11-12 03:10:28 +08:00
|
|
|
LBrace,
|
2012-01-28 03:52:33 +08:00
|
|
|
RBrace,
|
|
|
|
LSquare,
|
|
|
|
RSquare
|
2011-11-12 03:10:28 +08:00
|
|
|
} Kind;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
unsigned Location;
|
|
|
|
unsigned StringLength;
|
2017-06-02 09:55:39 +08:00
|
|
|
union {
|
|
|
|
// If Kind != IntegerLiteral.
|
|
|
|
const char *StringData;
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
// If Kind == IntegerLiteral.
|
|
|
|
uint64_t IntegerValue;
|
|
|
|
};
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
void clear() {
|
|
|
|
Kind = EndOfFile;
|
|
|
|
Location = 0;
|
|
|
|
StringLength = 0;
|
2014-05-18 07:10:59 +08:00
|
|
|
StringData = nullptr;
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
bool is(TokenKind K) const { return Kind == K; }
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
SourceLocation getLocation() const {
|
|
|
|
return SourceLocation::getFromRawEncoding(Location);
|
|
|
|
}
|
2017-06-02 09:55:39 +08:00
|
|
|
|
|
|
|
uint64_t getInteger() const {
|
|
|
|
return Kind == IntegerLiteral ? IntegerValue : 0;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
StringRef getString() const {
|
2017-06-02 09:55:39 +08:00
|
|
|
return Kind == IntegerLiteral ? StringRef()
|
|
|
|
: StringRef(StringData, StringLength);
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
};
|
2012-11-07 03:39:40 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
class ModuleMapParser {
|
|
|
|
Lexer &L;
|
|
|
|
SourceManager &SourceMgr;
|
2012-10-16 00:45:32 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Default target information, used only for string literal
|
2012-10-16 00:45:32 +08:00
|
|
|
/// parsing.
|
|
|
|
const TargetInfo *Target;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
DiagnosticsEngine &Diags;
|
|
|
|
ModuleMap ⤅
|
2014-04-15 02:00:01 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The current module map file.
|
2014-04-15 02:00:01 +08:00
|
|
|
const FileEntry *ModuleMapFile;
|
2018-06-01 09:26:18 +08:00
|
|
|
|
|
|
|
/// Source location of most recent parsed module declaration
|
|
|
|
SourceLocation CurrModuleDeclLoc;
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The directory that file names in this module map file should
|
2014-12-10 11:09:48 +08:00
|
|
|
/// be resolved relative to.
|
2011-11-12 05:55:48 +08:00
|
|
|
const DirectoryEntry *Directory;
|
2012-02-03 02:42:48 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Whether this module map is in a system header directory.
|
2013-06-22 00:28:10 +08:00
|
|
|
bool IsSystem;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Whether an error occurred.
|
2017-12-07 07:18:41 +08:00
|
|
|
bool HadError = false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Stores string data for the various string literals referenced
|
2011-11-12 03:10:28 +08:00
|
|
|
/// during parsing.
|
|
|
|
llvm::BumpPtrAllocator StringData;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The current token.
|
2011-11-12 03:10:28 +08:00
|
|
|
MMToken Tok;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The active module.
|
2017-12-07 07:18:41 +08:00
|
|
|
Module *ActiveModule = nullptr;
|
2015-08-14 01:13:33 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Whether a module uses the 'requires excluded' hack to mark its
|
2015-08-14 01:13:33 +08:00
|
|
|
/// contents as 'textual'.
|
|
|
|
///
|
|
|
|
/// On older Darwin SDK versions, 'requires excluded' is used to mark the
|
|
|
|
/// contents of the Darwin.C.excluded (assert.h) and Tcl.Private modules as
|
|
|
|
/// non-modular headers. For backwards compatibility, we continue to
|
|
|
|
/// support this idiom for just these modules, and map the headers to
|
|
|
|
/// 'textual' to match the original intent.
|
|
|
|
llvm::SmallPtrSet<Module *, 2> UsesRequiresExcludedHack;
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Consume the current token and return its location.
|
2011-11-12 03:10:28 +08:00
|
|
|
SourceLocation consumeToken();
|
2018-01-05 10:33:18 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Skip tokens until we reach the a token with the given kind
|
2011-11-12 03:10:28 +08:00
|
|
|
/// (or the end of the file).
|
|
|
|
void skipUntil(MMToken::TokenKind K);
|
2011-12-07 10:23:45 +08:00
|
|
|
|
2017-12-07 07:18:41 +08:00
|
|
|
using ModuleId = SmallVector<std::pair<std::string, SourceLocation>, 2>;
|
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
bool parseModuleId(ModuleId &Id);
|
2011-11-12 03:10:28 +08:00
|
|
|
void parseModuleDecl();
|
2013-09-11 15:20:44 +08:00
|
|
|
void parseExternModuleDecl();
|
2011-12-31 12:05:44 +08:00
|
|
|
void parseRequiresDecl();
|
2017-12-07 07:18:41 +08:00
|
|
|
void parseHeaderDecl(MMToken::TokenKind, SourceLocation LeadingLoc);
|
2011-12-09 03:11:24 +08:00
|
|
|
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
|
2011-12-02 09:47:07 +08:00
|
|
|
void parseExportDecl();
|
2017-09-15 07:38:44 +08:00
|
|
|
void parseExportAsDecl();
|
2013-09-24 17:14:14 +08:00
|
|
|
void parseUseDecl();
|
2013-01-15 01:21:00 +08:00
|
|
|
void parseLinkDecl();
|
2013-03-20 08:22:05 +08:00
|
|
|
void parseConfigMacros();
|
2013-03-21 05:10:35 +08:00
|
|
|
void parseConflict();
|
2012-11-07 03:39:40 +08:00
|
|
|
void parseInferredModuleDecl(bool Framework, bool Explicit);
|
2015-01-14 01:47:44 +08:00
|
|
|
|
2018-06-16 04:13:28 +08:00
|
|
|
/// Private modules are canonicalized as Foo_Private. Clang provides extra
|
|
|
|
/// module map search logic to find the appropriate private module when PCH
|
|
|
|
/// is used with implicit module maps. Warn when private modules are written
|
|
|
|
/// in other ways (FooPrivate and Foo.Private), providing notes and fixits.
|
|
|
|
void diagnosePrivateModules(SourceLocation ExplicitLoc,
|
|
|
|
SourceLocation FrameworkLoc);
|
|
|
|
|
2017-12-07 07:18:41 +08:00
|
|
|
using Attributes = ModuleMap::Attributes;
|
|
|
|
|
2012-12-21 03:22:21 +08:00
|
|
|
bool parseOptionalAttributes(Attributes &Attrs);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
public:
|
2018-01-05 10:33:18 +08:00
|
|
|
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
|
|
|
|
const TargetInfo *Target, DiagnosticsEngine &Diags,
|
|
|
|
ModuleMap &Map, const FileEntry *ModuleMapFile,
|
2018-01-06 06:13:56 +08:00
|
|
|
const DirectoryEntry *Directory, bool IsSystem)
|
2017-12-07 07:18:41 +08:00
|
|
|
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
|
|
|
|
ModuleMapFile(ModuleMapFile), Directory(Directory),
|
2018-01-06 06:13:56 +08:00
|
|
|
IsSystem(IsSystem) {
|
2011-11-12 03:10:28 +08:00
|
|
|
Tok.clear();
|
|
|
|
consumeToken();
|
|
|
|
}
|
2018-01-05 10:33:18 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
bool parseModuleMapFile();
|
2017-05-06 06:18:51 +08:00
|
|
|
|
|
|
|
bool terminatedByDirective() { return false; }
|
|
|
|
SourceLocation getLocation() { return Tok.getLocation(); }
|
2011-11-12 03:10:28 +08:00
|
|
|
};
|
2017-12-07 07:18:41 +08:00
|
|
|
|
|
|
|
} // namespace clang
|
2011-11-12 03:10:28 +08:00
|
|
|
|
|
|
|
SourceLocation ModuleMapParser::consumeToken() {
|
|
|
|
SourceLocation Result = Tok.getLocation();
|
2017-05-06 06:18:51 +08:00
|
|
|
|
|
|
|
retry:
|
2011-11-12 03:10:28 +08:00
|
|
|
Tok.clear();
|
|
|
|
Token LToken;
|
|
|
|
L.LexFromRawLexer(LToken);
|
|
|
|
Tok.Location = LToken.getLocation().getRawEncoding();
|
|
|
|
switch (LToken.getKind()) {
|
2014-05-17 12:53:25 +08:00
|
|
|
case tok::raw_identifier: {
|
|
|
|
StringRef RI = LToken.getRawIdentifier();
|
|
|
|
Tok.StringData = RI.data();
|
|
|
|
Tok.StringLength = RI.size();
|
|
|
|
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(RI)
|
2013-03-20 08:22:05 +08:00
|
|
|
.Case("config_macros", MMToken::ConfigMacros)
|
2013-03-21 05:10:35 +08:00
|
|
|
.Case("conflict", MMToken::Conflict)
|
2012-10-15 14:28:11 +08:00
|
|
|
.Case("exclude", MMToken::ExcludeKeyword)
|
2011-11-12 03:10:28 +08:00
|
|
|
.Case("explicit", MMToken::ExplicitKeyword)
|
2011-12-02 09:47:07 +08:00
|
|
|
.Case("export", MMToken::ExportKeyword)
|
2017-09-15 07:38:44 +08:00
|
|
|
.Case("export_as", MMToken::ExportAsKeyword)
|
2013-09-11 15:20:44 +08:00
|
|
|
.Case("extern", MMToken::ExternKeyword)
|
2011-11-18 06:09:43 +08:00
|
|
|
.Case("framework", MMToken::FrameworkKeyword)
|
2013-03-20 08:22:05 +08:00
|
|
|
.Case("header", MMToken::HeaderKeyword)
|
2013-01-15 01:21:00 +08:00
|
|
|
.Case("link", MMToken::LinkKeyword)
|
2011-11-12 03:10:28 +08:00
|
|
|
.Case("module", MMToken::ModuleKeyword)
|
2013-06-21 05:14:14 +08:00
|
|
|
.Case("private", MMToken::PrivateKeyword)
|
2011-12-31 12:05:44 +08:00
|
|
|
.Case("requires", MMToken::RequiresKeyword)
|
2014-10-23 07:50:56 +08:00
|
|
|
.Case("textual", MMToken::TextualKeyword)
|
2011-11-12 03:10:28 +08:00
|
|
|
.Case("umbrella", MMToken::UmbrellaKeyword)
|
2013-09-24 17:14:14 +08:00
|
|
|
.Case("use", MMToken::UseKeyword)
|
2011-11-12 03:10:28 +08:00
|
|
|
.Default(MMToken::Identifier);
|
|
|
|
break;
|
2014-05-17 12:53:25 +08:00
|
|
|
}
|
2011-12-31 12:05:44 +08:00
|
|
|
|
|
|
|
case tok::comma:
|
|
|
|
Tok.Kind = MMToken::Comma;
|
|
|
|
break;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
case tok::eof:
|
|
|
|
Tok.Kind = MMToken::EndOfFile;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
case tok::l_brace:
|
|
|
|
Tok.Kind = MMToken::LBrace;
|
|
|
|
break;
|
|
|
|
|
2012-01-28 03:52:33 +08:00
|
|
|
case tok::l_square:
|
|
|
|
Tok.Kind = MMToken::LSquare;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
case tok::period:
|
|
|
|
Tok.Kind = MMToken::Period;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
case tok::r_brace:
|
|
|
|
Tok.Kind = MMToken::RBrace;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-01-28 03:52:33 +08:00
|
|
|
case tok::r_square:
|
|
|
|
Tok.Kind = MMToken::RSquare;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
case tok::star:
|
|
|
|
Tok.Kind = MMToken::Star;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-10-29 06:18:19 +08:00
|
|
|
case tok::exclaim:
|
|
|
|
Tok.Kind = MMToken::Exclaim;
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
case tok::string_literal: {
|
2012-03-06 11:21:47 +08:00
|
|
|
if (LToken.hasUDSuffix()) {
|
|
|
|
Diags.Report(LToken.getLocation(), diag::err_invalid_string_udl);
|
|
|
|
HadError = true;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Parse the string literal.
|
|
|
|
LangOptions LangOpts;
|
2014-06-26 12:58:39 +08:00
|
|
|
StringLiteralParser StringLiteral(LToken, SourceMgr, LangOpts, *Target);
|
2011-11-12 03:10:28 +08:00
|
|
|
if (StringLiteral.hadError)
|
|
|
|
goto retry;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Copy the string literal into our string data allocator.
|
|
|
|
unsigned Length = StringLiteral.GetStringLength();
|
|
|
|
char *Saved = StringData.Allocate<char>(Length + 1);
|
|
|
|
memcpy(Saved, StringLiteral.GetString().data(), Length);
|
|
|
|
Saved[Length] = 0;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Form the token.
|
|
|
|
Tok.Kind = MMToken::StringLiteral;
|
|
|
|
Tok.StringData = Saved;
|
|
|
|
Tok.StringLength = Length;
|
|
|
|
break;
|
|
|
|
}
|
2017-06-02 09:55:39 +08:00
|
|
|
|
|
|
|
case tok::numeric_constant: {
|
|
|
|
// We don't support any suffixes or other complications.
|
|
|
|
SmallString<32> SpellingBuffer;
|
|
|
|
SpellingBuffer.resize(LToken.getLength() + 1);
|
|
|
|
const char *Start = SpellingBuffer.data();
|
|
|
|
unsigned Length =
|
|
|
|
Lexer::getSpelling(LToken, Start, SourceMgr, L.getLangOpts());
|
|
|
|
uint64_t Value;
|
|
|
|
if (StringRef(Start, Length).getAsInteger(0, Value)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
|
|
|
|
HadError = true;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
Tok.Kind = MMToken::IntegerLiteral;
|
|
|
|
Tok.IntegerValue = Value;
|
|
|
|
break;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
case tok::comment:
|
|
|
|
goto retry;
|
2017-05-06 06:18:51 +08:00
|
|
|
|
|
|
|
case tok::hash:
|
|
|
|
// A module map can be terminated prematurely by
|
|
|
|
// #pragma clang module contents
|
|
|
|
// When building the module, we'll treat the rest of the file as the
|
|
|
|
// contents of the module.
|
|
|
|
{
|
|
|
|
auto NextIsIdent = [&](StringRef Str) -> bool {
|
|
|
|
L.LexFromRawLexer(LToken);
|
|
|
|
return !LToken.isAtStartOfLine() && LToken.is(tok::raw_identifier) &&
|
|
|
|
LToken.getRawIdentifier() == Str;
|
|
|
|
};
|
|
|
|
if (NextIsIdent("pragma") && NextIsIdent("clang") &&
|
|
|
|
NextIsIdent("module") && NextIsIdent("contents")) {
|
|
|
|
Tok.Kind = MMToken::EndOfFile;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
default:
|
2017-05-06 06:18:51 +08:00
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_unknown_token);
|
2011-11-12 03:10:28 +08:00
|
|
|
HadError = true;
|
|
|
|
goto retry;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleMapParser::skipUntil(MMToken::TokenKind K) {
|
|
|
|
unsigned braceDepth = 0;
|
2012-01-28 03:52:33 +08:00
|
|
|
unsigned squareDepth = 0;
|
2011-11-12 03:10:28 +08:00
|
|
|
do {
|
|
|
|
switch (Tok.Kind) {
|
|
|
|
case MMToken::EndOfFile:
|
|
|
|
return;
|
|
|
|
|
|
|
|
case MMToken::LBrace:
|
2012-01-28 03:52:33 +08:00
|
|
|
if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
|
2011-11-12 03:10:28 +08:00
|
|
|
return;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
++braceDepth;
|
|
|
|
break;
|
2012-01-28 03:52:33 +08:00
|
|
|
|
|
|
|
case MMToken::LSquare:
|
|
|
|
if (Tok.is(K) && braceDepth == 0 && squareDepth == 0)
|
|
|
|
return;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-01-28 03:52:33 +08:00
|
|
|
++squareDepth;
|
|
|
|
break;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::RBrace:
|
|
|
|
if (braceDepth > 0)
|
|
|
|
--braceDepth;
|
|
|
|
else if (Tok.is(K))
|
|
|
|
return;
|
|
|
|
break;
|
2012-01-28 03:52:33 +08:00
|
|
|
|
|
|
|
case MMToken::RSquare:
|
|
|
|
if (squareDepth > 0)
|
|
|
|
--squareDepth;
|
|
|
|
else if (Tok.is(K))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
default:
|
2012-01-28 03:52:33 +08:00
|
|
|
if (braceDepth == 0 && squareDepth == 0 && Tok.is(K))
|
2011-11-12 03:10:28 +08:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
consumeToken();
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a module-id.
|
2011-12-07 10:23:45 +08:00
|
|
|
///
|
|
|
|
/// module-id:
|
|
|
|
/// identifier
|
|
|
|
/// identifier '.' module-id
|
|
|
|
///
|
|
|
|
/// \returns true if an error occurred, false otherwise.
|
|
|
|
bool ModuleMapParser::parseModuleId(ModuleId &Id) {
|
|
|
|
Id.clear();
|
|
|
|
do {
|
2013-12-06 17:25:54 +08:00
|
|
|
if (Tok.is(MMToken::Identifier) || Tok.is(MMToken::StringLiteral)) {
|
2011-12-07 10:23:45 +08:00
|
|
|
Id.push_back(std::make_pair(Tok.getString(), Tok.getLocation()));
|
|
|
|
consumeToken();
|
|
|
|
} else {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module_name);
|
|
|
|
return true;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
if (!Tok.is(MMToken::Period))
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
consumeToken();
|
|
|
|
} while (true);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-01-28 03:52:33 +08:00
|
|
|
namespace {
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Enumerates the known attributes.
|
2012-01-28 03:52:33 +08:00
|
|
|
enum AttributeKind {
|
2018-05-09 09:00:01 +08:00
|
|
|
/// An unknown attribute.
|
2012-01-28 03:52:33 +08:00
|
|
|
AT_unknown,
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The 'system' attribute.
|
2013-03-20 08:22:05 +08:00
|
|
|
AT_system,
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The 'extern_c' attribute.
|
2014-03-02 13:58:18 +08:00
|
|
|
AT_extern_c,
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The 'exhaustive' attribute.
|
2016-10-21 09:41:56 +08:00
|
|
|
AT_exhaustive,
|
2017-12-07 07:18:41 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// The 'no_undeclared_includes' attribute.
|
2016-10-21 09:41:56 +08:00
|
|
|
AT_no_undeclared_includes
|
2012-01-28 03:52:33 +08:00
|
|
|
};
|
2017-12-07 07:18:41 +08:00
|
|
|
|
|
|
|
} // namespace
|
2012-01-28 03:52:33 +08:00
|
|
|
|
2017-12-22 10:53:30 +08:00
|
|
|
/// Private modules are canonicalized as Foo_Private. Clang provides extra
|
|
|
|
/// module map search logic to find the appropriate private module when PCH
|
|
|
|
/// is used with implicit module maps. Warn when private modules are written
|
|
|
|
/// in other ways (FooPrivate and Foo.Private), providing notes and fixits.
|
2018-06-16 04:13:28 +08:00
|
|
|
void ModuleMapParser::diagnosePrivateModules(SourceLocation ExplicitLoc,
|
|
|
|
SourceLocation FrameworkLoc) {
|
2017-12-22 10:53:30 +08:00
|
|
|
auto GenNoteAndFixIt = [&](StringRef BadName, StringRef Canonical,
|
2018-03-30 13:17:58 +08:00
|
|
|
const Module *M, SourceRange ReplLoc) {
|
2017-12-22 10:53:30 +08:00
|
|
|
auto D = Diags.Report(ActiveModule->DefinitionLoc,
|
|
|
|
diag::note_mmap_rename_top_level_private_module);
|
|
|
|
D << BadName << M->Name;
|
2018-03-30 13:17:58 +08:00
|
|
|
D << FixItHint::CreateReplacement(ReplLoc, Canonical);
|
2017-12-22 10:53:30 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
for (auto E = Map.module_begin(); E != Map.module_end(); ++E) {
|
|
|
|
auto const *M = E->getValue();
|
|
|
|
if (M->Directory != ActiveModule->Directory)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SmallString<128> FullName(ActiveModule->getFullModuleName());
|
|
|
|
if (!FullName.startswith(M->Name) && !FullName.endswith("Private"))
|
|
|
|
continue;
|
2018-06-16 04:13:28 +08:00
|
|
|
SmallString<128> FixedPrivModDecl;
|
2017-12-22 10:53:30 +08:00
|
|
|
SmallString<128> Canonical(M->Name);
|
|
|
|
Canonical.append("_Private");
|
|
|
|
|
|
|
|
// Foo.Private -> Foo_Private
|
|
|
|
if (ActiveModule->Parent && ActiveModule->Name == "Private" && !M->Parent &&
|
|
|
|
M->Name == ActiveModule->Parent->Name) {
|
|
|
|
Diags.Report(ActiveModule->DefinitionLoc,
|
|
|
|
diag::warn_mmap_mismatched_private_submodule)
|
|
|
|
<< FullName;
|
2018-06-16 04:13:28 +08:00
|
|
|
|
|
|
|
SourceLocation FixItInitBegin = CurrModuleDeclLoc;
|
|
|
|
if (FrameworkLoc.isValid())
|
|
|
|
FixItInitBegin = FrameworkLoc;
|
|
|
|
if (ExplicitLoc.isValid())
|
|
|
|
FixItInitBegin = ExplicitLoc;
|
|
|
|
|
|
|
|
if (FrameworkLoc.isValid() || ActiveModule->Parent->IsFramework)
|
|
|
|
FixedPrivModDecl.append("framework ");
|
|
|
|
FixedPrivModDecl.append("module ");
|
|
|
|
FixedPrivModDecl.append(Canonical);
|
|
|
|
|
|
|
|
GenNoteAndFixIt(FullName, FixedPrivModDecl, M,
|
|
|
|
SourceRange(FixItInitBegin, ActiveModule->DefinitionLoc));
|
2017-12-22 10:53:30 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FooPrivate and whatnots -> Foo_Private
|
|
|
|
if (!ActiveModule->Parent && !M->Parent && M->Name != ActiveModule->Name &&
|
|
|
|
ActiveModule->Name != Canonical) {
|
|
|
|
Diags.Report(ActiveModule->DefinitionLoc,
|
|
|
|
diag::warn_mmap_mismatched_private_module_name)
|
|
|
|
<< ActiveModule->Name;
|
2018-03-30 13:17:58 +08:00
|
|
|
GenNoteAndFixIt(ActiveModule->Name, Canonical, M,
|
|
|
|
SourceRange(ActiveModule->DefinitionLoc));
|
2017-12-22 10:53:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a module declaration.
|
2011-11-12 03:10:28 +08:00
|
|
|
///
|
|
|
|
/// module-declaration:
|
2013-09-11 15:20:44 +08:00
|
|
|
/// 'extern' 'module' module-id string-literal
|
2018-07-31 03:24:48 +08:00
|
|
|
/// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt]
|
2012-01-28 03:52:33 +08:00
|
|
|
/// { module-member* }
|
|
|
|
///
|
2011-11-12 03:10:28 +08:00
|
|
|
/// module-member:
|
2011-12-31 12:05:44 +08:00
|
|
|
/// requires-declaration
|
2011-11-12 03:10:28 +08:00
|
|
|
/// header-declaration
|
2011-12-07 10:23:45 +08:00
|
|
|
/// submodule-declaration
|
2011-12-02 09:47:07 +08:00
|
|
|
/// export-declaration
|
2017-09-15 07:38:44 +08:00
|
|
|
/// export-as-declaration
|
2013-01-15 01:21:00 +08:00
|
|
|
/// link-declaration
|
2011-12-06 06:27:44 +08:00
|
|
|
///
|
|
|
|
/// submodule-declaration:
|
|
|
|
/// module-declaration
|
|
|
|
/// inferred-submodule-declaration
|
2011-11-12 03:10:28 +08:00
|
|
|
void ModuleMapParser::parseModuleDecl() {
|
2011-11-18 06:09:43 +08:00
|
|
|
assert(Tok.is(MMToken::ExplicitKeyword) || Tok.is(MMToken::ModuleKeyword) ||
|
2013-09-11 15:20:44 +08:00
|
|
|
Tok.is(MMToken::FrameworkKeyword) || Tok.is(MMToken::ExternKeyword));
|
|
|
|
if (Tok.is(MMToken::ExternKeyword)) {
|
|
|
|
parseExternModuleDecl();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-12-07 01:16:41 +08:00
|
|
|
// Parse 'explicit' or 'framework' keyword, if present.
|
2011-12-07 10:23:45 +08:00
|
|
|
SourceLocation ExplicitLoc;
|
2018-06-16 04:13:28 +08:00
|
|
|
SourceLocation FrameworkLoc;
|
2011-11-12 03:10:28 +08:00
|
|
|
bool Explicit = false;
|
2011-12-07 01:16:41 +08:00
|
|
|
bool Framework = false;
|
2011-11-18 06:09:43 +08:00
|
|
|
|
|
|
|
// Parse 'explicit' keyword, if present.
|
2011-12-07 01:16:41 +08:00
|
|
|
if (Tok.is(MMToken::ExplicitKeyword)) {
|
2011-12-07 10:23:45 +08:00
|
|
|
ExplicitLoc = consumeToken();
|
2011-11-12 03:10:28 +08:00
|
|
|
Explicit = true;
|
|
|
|
}
|
2011-12-07 01:16:41 +08:00
|
|
|
|
|
|
|
// Parse 'framework' keyword, if present.
|
|
|
|
if (Tok.is(MMToken::FrameworkKeyword)) {
|
2018-06-16 04:13:28 +08:00
|
|
|
FrameworkLoc = consumeToken();
|
2011-12-07 01:16:41 +08:00
|
|
|
Framework = true;
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Parse 'module' keyword.
|
|
|
|
if (!Tok.is(MMToken::ModuleKeyword)) {
|
2011-12-07 03:57:48 +08:00
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
|
2011-11-12 03:10:28 +08:00
|
|
|
consumeToken();
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2018-06-01 09:26:18 +08:00
|
|
|
CurrModuleDeclLoc = consumeToken(); // 'module' keyword
|
2011-12-06 06:27:44 +08:00
|
|
|
|
|
|
|
// If we have a wildcard for the module name, this is an inferred submodule.
|
2018-07-31 03:24:48 +08:00
|
|
|
// Parse it.
|
2011-12-06 06:27:44 +08:00
|
|
|
if (Tok.is(MMToken::Star))
|
2012-11-07 03:39:40 +08:00
|
|
|
return parseInferredModuleDecl(Framework, Explicit);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Parse the module name.
|
2011-12-07 10:23:45 +08:00
|
|
|
ModuleId Id;
|
|
|
|
if (parseModuleId(Id)) {
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2012-11-07 03:39:40 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
if (ActiveModule) {
|
|
|
|
if (Id.size() > 1) {
|
|
|
|
Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id)
|
|
|
|
<< SourceRange(Id.front().second, Id.back().second);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (Id.size() == 1 && Explicit) {
|
|
|
|
// Top-level modules can't be explicit.
|
|
|
|
Diags.Report(ExplicitLoc, diag::err_mmap_explicit_top_level);
|
|
|
|
Explicit = false;
|
|
|
|
ExplicitLoc = SourceLocation();
|
2011-11-12 03:10:28 +08:00
|
|
|
HadError = true;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
Module *PreviousActiveModule = ActiveModule;
|
2011-12-07 10:23:45 +08:00
|
|
|
if (Id.size() > 1) {
|
|
|
|
// This module map defines a submodule. Go find the module of which it
|
|
|
|
// is a submodule.
|
2014-05-18 07:10:59 +08:00
|
|
|
ActiveModule = nullptr;
|
2014-08-13 00:42:33 +08:00
|
|
|
const Module *TopLevelModule = nullptr;
|
2011-12-07 10:23:45 +08:00
|
|
|
for (unsigned I = 0, N = Id.size() - 1; I != N; ++I) {
|
|
|
|
if (Module *Next = Map.lookupModuleQualified(Id[I].first, ActiveModule)) {
|
2014-08-13 00:42:33 +08:00
|
|
|
if (I == 0)
|
|
|
|
TopLevelModule = Next;
|
2011-12-07 10:23:45 +08:00
|
|
|
ActiveModule = Next;
|
|
|
|
continue;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
if (ActiveModule) {
|
|
|
|
Diags.Report(Id[I].second, diag::err_mmap_missing_module_qualified)
|
2014-03-13 07:36:42 +08:00
|
|
|
<< Id[I].first
|
|
|
|
<< ActiveModule->getTopLevelModule()->getFullModuleName();
|
2011-12-07 10:23:45 +08:00
|
|
|
} else {
|
|
|
|
Diags.Report(Id[I].second, diag::err_mmap_expected_module_name);
|
|
|
|
}
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2014-08-13 00:42:33 +08:00
|
|
|
|
|
|
|
if (ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) {
|
|
|
|
assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) &&
|
|
|
|
"submodule defined in same file as 'module *' that allowed its "
|
|
|
|
"top-level module");
|
|
|
|
Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile);
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
StringRef ModuleName = Id.back().first;
|
|
|
|
SourceLocation ModuleNameLoc = Id.back().second;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-01-28 03:52:33 +08:00
|
|
|
// Parse the optional attribute list.
|
2012-12-21 03:22:21 +08:00
|
|
|
Attributes Attrs;
|
2016-03-06 12:20:05 +08:00
|
|
|
if (parseOptionalAttributes(Attrs))
|
|
|
|
return;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Parse the opening brace.
|
|
|
|
if (!Tok.is(MMToken::LBrace)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace)
|
|
|
|
<< ModuleName;
|
|
|
|
HadError = true;
|
|
|
|
return;
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
2011-11-12 03:10:28 +08:00
|
|
|
SourceLocation LBraceLoc = consumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Determine whether this (sub)module has already been defined.
|
2018-01-05 10:33:18 +08:00
|
|
|
Module *ShadowingModule = nullptr;
|
2012-01-05 07:32:19 +08:00
|
|
|
if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
|
2017-05-09 04:30:47 +08:00
|
|
|
// We might see a (re)definition of a module that we already have a
|
|
|
|
// definition for in two cases:
|
|
|
|
// - If we loaded one definition from an AST file and we've just found a
|
|
|
|
// corresponding definition in a module map file, or
|
|
|
|
bool LoadedFromASTFile = Existing->DefinitionLoc.isInvalid();
|
|
|
|
// - If we're building a (preprocessed) module and we've just loaded the
|
|
|
|
// module map file from which it was created.
|
|
|
|
bool ParsedAsMainInput =
|
|
|
|
Map.LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap &&
|
|
|
|
Map.LangOpts.CurrentModule == ModuleName &&
|
|
|
|
SourceMgr.getDecomposedLoc(ModuleNameLoc).first !=
|
|
|
|
SourceMgr.getDecomposedLoc(Existing->DefinitionLoc).first;
|
|
|
|
if (!ActiveModule && (LoadedFromASTFile || ParsedAsMainInput)) {
|
2012-01-05 08:12:00 +08:00
|
|
|
// Skip the module definition.
|
|
|
|
skipUntil(MMToken::RBrace);
|
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
else {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
|
|
|
|
Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
|
2018-07-31 03:24:48 +08:00
|
|
|
HadError = true;
|
2012-01-05 08:12:00 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2018-01-05 10:33:18 +08:00
|
|
|
|
2018-01-06 06:13:56 +08:00
|
|
|
if (!Existing->Parent && Map.mayShadowNewModule(Existing)) {
|
2018-01-05 10:33:18 +08:00
|
|
|
ShadowingModule = Existing;
|
|
|
|
} else {
|
|
|
|
// This is not a shawdowed module decl, it is an illegal redefinition.
|
|
|
|
Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
|
|
|
|
<< ModuleName;
|
|
|
|
Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
|
|
|
|
|
|
|
|
// Skip the module definition.
|
|
|
|
skipUntil(MMToken::RBrace);
|
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Start defining this module.
|
2018-01-05 10:33:18 +08:00
|
|
|
if (ShadowingModule) {
|
|
|
|
ActiveModule =
|
|
|
|
Map.createShadowedModule(ModuleName, Framework, ShadowingModule);
|
|
|
|
} else {
|
2018-01-06 06:13:56 +08:00
|
|
|
ActiveModule =
|
|
|
|
Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit)
|
|
|
|
.first;
|
2018-01-05 10:33:18 +08:00
|
|
|
}
|
|
|
|
|
2012-01-05 07:32:19 +08:00
|
|
|
ActiveModule->DefinitionLoc = ModuleNameLoc;
|
2013-06-22 00:28:10 +08:00
|
|
|
if (Attrs.IsSystem || IsSystem)
|
2012-01-28 03:52:33 +08:00
|
|
|
ActiveModule->IsSystem = true;
|
2014-03-02 13:58:18 +08:00
|
|
|
if (Attrs.IsExternC)
|
|
|
|
ActiveModule->IsExternC = true;
|
2016-10-21 09:41:56 +08:00
|
|
|
if (Attrs.NoUndeclaredIncludes ||
|
|
|
|
(!ActiveModule->Parent && ModuleName == "Darwin"))
|
|
|
|
ActiveModule->NoUndeclaredIncludes = true;
|
2014-12-02 08:08:08 +08:00
|
|
|
ActiveModule->Directory = Directory;
|
2014-03-02 13:58:18 +08:00
|
|
|
|
2018-04-21 01:16:04 +08:00
|
|
|
StringRef MapFileName(ModuleMapFile->getName());
|
|
|
|
if (MapFileName.endswith("module.private.modulemap") ||
|
|
|
|
MapFileName.endswith("module_private.map")) {
|
|
|
|
ActiveModule->ModuleMapIsPrivate = true;
|
|
|
|
}
|
2017-12-22 10:53:30 +08:00
|
|
|
|
|
|
|
// Private modules named as FooPrivate, Foo.Private or similar are likely a
|
|
|
|
// user error; provide warnings, notes and fixits to direct users to use
|
|
|
|
// Foo_Private instead.
|
|
|
|
SourceLocation StartLoc =
|
|
|
|
SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
|
|
|
|
if (Map.HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
|
|
|
|
!Diags.isIgnored(diag::warn_mmap_mismatched_private_submodule,
|
|
|
|
StartLoc) &&
|
|
|
|
!Diags.isIgnored(diag::warn_mmap_mismatched_private_module_name,
|
|
|
|
StartLoc) &&
|
2018-04-21 01:16:04 +08:00
|
|
|
ActiveModule->ModuleMapIsPrivate)
|
2018-06-16 04:13:28 +08:00
|
|
|
diagnosePrivateModules(ExplicitLoc, FrameworkLoc);
|
[modules] Handle modules with nonstandard names in module.private.modulemaps
Summary:
The module system supports accompanying a primary module (say Foo) with
an auxiliary "private" module (defined in an adjacent module.private.modulemap
file) that augments the primary module when associated private headers are
available. The feature is intended to be used to augment the primary
module with a submodule (say Foo.Private), however some users in the wild
are choosing to augment the primary module with an additional top-level module
with a "similar" name (in all cases so far: FooPrivate).
This "works" when a user of the module initially imports a private header,
such as '#import "Foo/something_private.h"' since the Foo import winds up
importing FooPrivate in passing. But if the import is subsequently recorded
in a PCH file, reloading the PCH will fail to validate because of a cross-check
that attempts to find the module.modulemap (or module.private.modulemap) using
HeaderSearch algorithm, applied to the "FooPrivate" name. Since it's stored in
Foo.framework/Modules, not FooPrivate.framework/Modules, the check fails and
the PCH is rejected.
This patch adds a compensatory workaround in the HeaderSearch algorithm
when searching (and failing to find) a module of the form FooPrivate: the
name used to derive filesystem paths is decoupled from the module name
being searched for, and if the initial search fails and the module is
named "FooPrivate", the filesystem search name is altered to remove the
"Private" suffix, and the algorithm is run a second time (still looking for
a module named FooPrivate, but looking in directories derived from Foo).
Accompanying this change is a new warning that triggers when a user loads
a module.private.modulemap that defines a top-level module with a different
name from the top-level module defined in its adjacent module.modulemap.
Reviewers: doug.gregor, manmanren, bruno
Subscribers: bruno, cfe-commits
Differential Revision: https://reviews.llvm.org/D27852
llvm-svn: 290219
2016-12-21 08:24:39 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
bool Done = false;
|
|
|
|
do {
|
|
|
|
switch (Tok.Kind) {
|
|
|
|
case MMToken::EndOfFile:
|
|
|
|
case MMToken::RBrace:
|
|
|
|
Done = true;
|
|
|
|
break;
|
2013-03-20 08:22:05 +08:00
|
|
|
|
|
|
|
case MMToken::ConfigMacros:
|
|
|
|
parseConfigMacros();
|
|
|
|
break;
|
|
|
|
|
2013-03-21 05:10:35 +08:00
|
|
|
case MMToken::Conflict:
|
|
|
|
parseConflict();
|
|
|
|
break;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::ExplicitKeyword:
|
2013-09-11 15:20:44 +08:00
|
|
|
case MMToken::ExternKeyword:
|
2011-12-07 01:16:41 +08:00
|
|
|
case MMToken::FrameworkKeyword:
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::ModuleKeyword:
|
|
|
|
parseModuleDecl();
|
|
|
|
break;
|
2013-09-11 15:20:44 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
case MMToken::ExportKeyword:
|
|
|
|
parseExportDecl();
|
|
|
|
break;
|
2013-09-24 17:14:14 +08:00
|
|
|
|
2017-09-15 07:38:44 +08:00
|
|
|
case MMToken::ExportAsKeyword:
|
|
|
|
parseExportAsDecl();
|
|
|
|
break;
|
|
|
|
|
2013-09-24 17:14:14 +08:00
|
|
|
case MMToken::UseKeyword:
|
|
|
|
parseUseDecl();
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
case MMToken::RequiresKeyword:
|
|
|
|
parseRequiresDecl();
|
|
|
|
break;
|
|
|
|
|
2014-10-25 04:23:01 +08:00
|
|
|
case MMToken::TextualKeyword:
|
|
|
|
parseHeaderDecl(MMToken::TextualKeyword, consumeToken());
|
2014-10-23 07:50:56 +08:00
|
|
|
break;
|
|
|
|
|
2011-12-09 03:11:24 +08:00
|
|
|
case MMToken::UmbrellaKeyword: {
|
|
|
|
SourceLocation UmbrellaLoc = consumeToken();
|
|
|
|
if (Tok.is(MMToken::HeaderKeyword))
|
2013-06-21 05:14:14 +08:00
|
|
|
parseHeaderDecl(MMToken::UmbrellaKeyword, UmbrellaLoc);
|
2011-12-09 03:11:24 +08:00
|
|
|
else
|
|
|
|
parseUmbrellaDirDecl(UmbrellaLoc);
|
2011-11-12 03:10:28 +08:00
|
|
|
break;
|
2011-12-09 03:11:24 +08:00
|
|
|
}
|
2014-10-25 04:23:01 +08:00
|
|
|
|
|
|
|
case MMToken::ExcludeKeyword:
|
|
|
|
parseHeaderDecl(MMToken::ExcludeKeyword, consumeToken());
|
2012-10-15 14:28:11 +08:00
|
|
|
break;
|
2014-10-25 04:23:01 +08:00
|
|
|
|
|
|
|
case MMToken::PrivateKeyword:
|
|
|
|
parseHeaderDecl(MMToken::PrivateKeyword, consumeToken());
|
2013-06-21 05:14:14 +08:00
|
|
|
break;
|
2014-10-25 04:23:01 +08:00
|
|
|
|
2011-12-09 02:00:48 +08:00
|
|
|
case MMToken::HeaderKeyword:
|
2014-10-25 04:23:01 +08:00
|
|
|
parseHeaderDecl(MMToken::HeaderKeyword, consumeToken());
|
2011-11-12 03:10:28 +08:00
|
|
|
break;
|
2013-01-15 01:21:00 +08:00
|
|
|
|
|
|
|
case MMToken::LinkKeyword:
|
|
|
|
parseLinkDecl();
|
|
|
|
break;
|
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
default:
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
|
|
|
|
consumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
break;
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
} while (!Done);
|
|
|
|
|
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
else {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
|
|
|
|
Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
|
|
|
|
HadError = true;
|
|
|
|
}
|
|
|
|
|
2013-01-15 01:57:51 +08:00
|
|
|
// If the active module is a top-level framework, and there are no link
|
|
|
|
// libraries, automatically link against the framework.
|
|
|
|
if (ActiveModule->IsFramework && !ActiveModule->isSubFramework() &&
|
|
|
|
ActiveModule->LinkLibraries.empty()) {
|
|
|
|
inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager());
|
|
|
|
}
|
|
|
|
|
2014-04-19 06:07:31 +08:00
|
|
|
// If the module meets all requirements but is still unavailable, mark the
|
|
|
|
// whole tree as unavailable to prevent it from building.
|
|
|
|
if (!ActiveModule->IsAvailable && !ActiveModule->IsMissingRequirement &&
|
|
|
|
ActiveModule->Parent) {
|
|
|
|
ActiveModule->getTopLevelModule()->markUnavailable();
|
|
|
|
ActiveModule->getTopLevelModule()->MissingHeaders.append(
|
|
|
|
ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end());
|
|
|
|
}
|
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
// We're done parsing this module. Pop back to the previous module.
|
|
|
|
ActiveModule = PreviousActiveModule;
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
2011-12-07 01:16:41 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse an extern module declaration.
|
2013-09-11 15:20:44 +08:00
|
|
|
///
|
|
|
|
/// extern module-declaration:
|
|
|
|
/// 'extern' 'module' module-id string-literal
|
|
|
|
void ModuleMapParser::parseExternModuleDecl() {
|
|
|
|
assert(Tok.is(MMToken::ExternKeyword));
|
2015-07-14 10:06:01 +08:00
|
|
|
SourceLocation ExternLoc = consumeToken(); // 'extern' keyword
|
2013-09-11 15:20:44 +08:00
|
|
|
|
|
|
|
// Parse 'module' keyword.
|
|
|
|
if (!Tok.is(MMToken::ModuleKeyword)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
|
|
|
|
consumeToken();
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
consumeToken(); // 'module' keyword
|
|
|
|
|
|
|
|
// Parse the module name.
|
|
|
|
ModuleId Id;
|
|
|
|
if (parseModuleId(Id)) {
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the referenced module map file name.
|
|
|
|
if (!Tok.is(MMToken::StringLiteral)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_mmap_file);
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::string FileName = Tok.getString();
|
|
|
|
consumeToken(); // filename
|
|
|
|
|
|
|
|
StringRef FileNameRef = FileName;
|
|
|
|
SmallString<128> ModuleMapFileName;
|
|
|
|
if (llvm::sys::path::is_relative(FileNameRef)) {
|
|
|
|
ModuleMapFileName += Directory->getName();
|
|
|
|
llvm::sys::path::append(ModuleMapFileName, FileName);
|
2015-03-18 18:17:07 +08:00
|
|
|
FileNameRef = ModuleMapFileName;
|
2013-09-11 15:20:44 +08:00
|
|
|
}
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto File = SourceMgr.getFileManager().getFile(FileNameRef))
|
2014-12-10 11:09:48 +08:00
|
|
|
Map.parseModuleMapFile(
|
2019-08-02 05:31:56 +08:00
|
|
|
*File, /*IsSystem=*/false,
|
2014-12-10 11:09:48 +08:00
|
|
|
Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd
|
|
|
|
? Directory
|
2019-08-02 05:31:56 +08:00
|
|
|
: (*File)->getDir(),
|
2018-01-06 06:13:56 +08:00
|
|
|
FileID(), nullptr, ExternLoc);
|
2013-09-11 15:20:44 +08:00
|
|
|
}
|
|
|
|
|
2015-08-14 01:13:33 +08:00
|
|
|
/// Whether to add the requirement \p Feature to the module \p M.
|
|
|
|
///
|
|
|
|
/// This preserves backwards compatibility for two hacks in the Darwin system
|
|
|
|
/// module map files:
|
|
|
|
///
|
|
|
|
/// 1. The use of 'requires excluded' to make headers non-modular, which
|
|
|
|
/// should really be mapped to 'textual' now that we have this feature. We
|
|
|
|
/// drop the 'excluded' requirement, and set \p IsRequiresExcludedHack to
|
|
|
|
/// true. Later, this bit will be used to map all the headers inside this
|
|
|
|
/// module to 'textual'.
|
|
|
|
///
|
|
|
|
/// This affects Darwin.C.excluded (for assert.h) and Tcl.Private.
|
|
|
|
///
|
|
|
|
/// 2. Removes a bogus cplusplus requirement from IOKit.avc. This requirement
|
|
|
|
/// was never correct and causes issues now that we check it, so drop it.
|
|
|
|
static bool shouldAddRequirement(Module *M, StringRef Feature,
|
|
|
|
bool &IsRequiresExcludedHack) {
|
2016-11-16 02:56:39 +08:00
|
|
|
if (Feature == "excluded" &&
|
|
|
|
(M->fullModuleNameIs({"Darwin", "C", "excluded"}) ||
|
|
|
|
M->fullModuleNameIs({"Tcl", "Private"}))) {
|
2015-08-14 01:13:33 +08:00
|
|
|
IsRequiresExcludedHack = true;
|
|
|
|
return false;
|
2016-11-16 02:56:39 +08:00
|
|
|
} else if (Feature == "cplusplus" && M->fullModuleNameIs({"IOKit", "avc"})) {
|
2015-08-14 01:13:33 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a requires declaration.
|
2011-12-31 12:05:44 +08:00
|
|
|
///
|
|
|
|
/// requires-declaration:
|
|
|
|
/// 'requires' feature-list
|
|
|
|
///
|
|
|
|
/// feature-list:
|
2013-10-29 06:18:19 +08:00
|
|
|
/// feature ',' feature-list
|
|
|
|
/// feature
|
|
|
|
///
|
|
|
|
/// feature:
|
|
|
|
/// '!'[opt] identifier
|
2011-12-31 12:05:44 +08:00
|
|
|
void ModuleMapParser::parseRequiresDecl() {
|
|
|
|
assert(Tok.is(MMToken::RequiresKeyword));
|
|
|
|
|
|
|
|
// Parse 'requires' keyword.
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
// Parse the feature-list.
|
|
|
|
do {
|
2013-10-29 06:18:19 +08:00
|
|
|
bool RequiredState = true;
|
|
|
|
if (Tok.is(MMToken::Exclaim)) {
|
|
|
|
RequiredState = false;
|
|
|
|
consumeToken();
|
|
|
|
}
|
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
if (!Tok.is(MMToken::Identifier)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_feature);
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the feature name.
|
|
|
|
std::string Feature = Tok.getString();
|
|
|
|
consumeToken();
|
|
|
|
|
2015-08-14 01:13:33 +08:00
|
|
|
bool IsRequiresExcludedHack = false;
|
|
|
|
bool ShouldAddRequirement =
|
|
|
|
shouldAddRequirement(ActiveModule, Feature, IsRequiresExcludedHack);
|
|
|
|
|
|
|
|
if (IsRequiresExcludedHack)
|
|
|
|
UsesRequiresExcludedHack.insert(ActiveModule);
|
|
|
|
|
|
|
|
if (ShouldAddRequirement) {
|
|
|
|
// Add this feature.
|
|
|
|
ActiveModule->addRequirement(Feature, RequiredState, Map.LangOpts,
|
|
|
|
*Map.Target);
|
|
|
|
}
|
2011-12-31 12:05:44 +08:00
|
|
|
|
|
|
|
if (!Tok.is(MMToken::Comma))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Consume the comma.
|
|
|
|
consumeToken();
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a header declaration.
|
2011-11-12 03:10:28 +08:00
|
|
|
///
|
2011-12-09 02:00:48 +08:00
|
|
|
/// header-declaration:
|
2014-10-23 07:50:56 +08:00
|
|
|
/// 'textual'[opt] 'header' string-literal
|
2014-10-25 04:23:01 +08:00
|
|
|
/// 'private' 'textual'[opt] 'header' string-literal
|
|
|
|
/// 'exclude' 'header' string-literal
|
|
|
|
/// 'umbrella' 'header' string-literal
|
2014-10-23 07:50:56 +08:00
|
|
|
///
|
|
|
|
/// FIXME: Support 'private textual header'.
|
2013-06-21 05:14:14 +08:00
|
|
|
void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
|
|
|
|
SourceLocation LeadingLoc) {
|
2014-10-25 04:23:01 +08:00
|
|
|
// We've already consumed the first token.
|
|
|
|
ModuleMap::ModuleHeaderRole Role = ModuleMap::NormalHeader;
|
|
|
|
if (LeadingToken == MMToken::PrivateKeyword) {
|
|
|
|
Role = ModuleMap::PrivateHeader;
|
|
|
|
// 'private' may optionally be followed by 'textual'.
|
|
|
|
if (Tok.is(MMToken::TextualKeyword)) {
|
|
|
|
LeadingToken = Tok.Kind;
|
|
|
|
consumeToken();
|
|
|
|
}
|
|
|
|
}
|
2015-08-14 01:13:33 +08:00
|
|
|
|
2014-10-25 04:23:01 +08:00
|
|
|
if (LeadingToken == MMToken::TextualKeyword)
|
|
|
|
Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
|
|
|
|
|
2015-08-14 01:13:33 +08:00
|
|
|
if (UsesRequiresExcludedHack.count(ActiveModule)) {
|
|
|
|
// Mark this header 'textual' (see doc comment for
|
|
|
|
// Module::UsesRequiresExcludedHack).
|
|
|
|
Role = ModuleMap::ModuleHeaderRole(Role | ModuleMap::TextualHeader);
|
|
|
|
}
|
|
|
|
|
2014-10-25 04:23:01 +08:00
|
|
|
if (LeadingToken != MMToken::HeaderKeyword) {
|
|
|
|
if (!Tok.is(MMToken::HeaderKeyword)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
|
|
|
|
<< (LeadingToken == MMToken::PrivateKeyword ? "private" :
|
|
|
|
LeadingToken == MMToken::ExcludeKeyword ? "exclude" :
|
|
|
|
LeadingToken == MMToken::TextualKeyword ? "textual" : "umbrella");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
consumeToken();
|
|
|
|
}
|
2011-12-09 02:00:48 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Parse the header name.
|
|
|
|
if (!Tok.is(MMToken::StringLiteral)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
|
2011-12-09 02:00:48 +08:00
|
|
|
<< "header";
|
2011-11-12 03:10:28 +08:00
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2014-12-02 08:08:08 +08:00
|
|
|
Module::UnresolvedHeaderDirective Header;
|
2013-12-17 18:31:37 +08:00
|
|
|
Header.FileName = Tok.getString();
|
|
|
|
Header.FileNameLoc = consumeToken();
|
2017-05-26 08:01:53 +08:00
|
|
|
Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
|
2017-06-02 09:55:39 +08:00
|
|
|
Header.Kind =
|
|
|
|
(LeadingToken == MMToken::ExcludeKeyword ? Module::HK_Excluded
|
|
|
|
: Map.headerRoleToKind(Role));
|
2017-03-22 00:43:51 +08:00
|
|
|
|
2011-12-09 03:11:24 +08:00
|
|
|
// Check whether we already have an umbrella.
|
2017-05-26 08:01:53 +08:00
|
|
|
if (Header.IsUmbrella && ActiveModule->Umbrella) {
|
2013-12-17 18:31:37 +08:00
|
|
|
Diags.Report(Header.FileNameLoc, diag::err_mmap_umbrella_clash)
|
2011-12-09 03:11:24 +08:00
|
|
|
<< ActiveModule->getFullModuleName();
|
2011-11-12 05:55:48 +08:00
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2011-11-18 06:09:43 +08:00
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
// If we were given stat information, parse it so we can skip looking for
|
|
|
|
// the file.
|
|
|
|
if (Tok.is(MMToken::LBrace)) {
|
|
|
|
SourceLocation LBraceLoc = consumeToken();
|
|
|
|
|
|
|
|
while (!Tok.is(MMToken::RBrace) && !Tok.is(MMToken::EndOfFile)) {
|
|
|
|
enum Attribute { Size, ModTime, Unknown };
|
|
|
|
StringRef Str = Tok.getString();
|
|
|
|
SourceLocation Loc = consumeToken();
|
|
|
|
switch (llvm::StringSwitch<Attribute>(Str)
|
|
|
|
.Case("size", Size)
|
|
|
|
.Case("mtime", ModTime)
|
|
|
|
.Default(Unknown)) {
|
|
|
|
case Size:
|
|
|
|
if (Header.Size)
|
|
|
|
Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
|
|
|
|
if (!Tok.is(MMToken::IntegerLiteral)) {
|
|
|
|
Diags.Report(Tok.getLocation(),
|
|
|
|
diag::err_mmap_invalid_header_attribute_value) << Str;
|
|
|
|
skipUntil(MMToken::RBrace);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Header.Size = Tok.getInteger();
|
|
|
|
consumeToken();
|
|
|
|
break;
|
2017-05-26 08:01:53 +08:00
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
case ModTime:
|
|
|
|
if (Header.ModTime)
|
|
|
|
Diags.Report(Loc, diag::err_mmap_duplicate_header_attribute) << Str;
|
|
|
|
if (!Tok.is(MMToken::IntegerLiteral)) {
|
|
|
|
Diags.Report(Tok.getLocation(),
|
|
|
|
diag::err_mmap_invalid_header_attribute_value) << Str;
|
|
|
|
skipUntil(MMToken::RBrace);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Header.ModTime = Tok.getInteger();
|
|
|
|
consumeToken();
|
|
|
|
break;
|
2014-12-02 08:08:08 +08:00
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
case Unknown:
|
|
|
|
Diags.Report(Loc, diag::err_mmap_expected_header_attribute);
|
|
|
|
skipUntil(MMToken::RBrace);
|
|
|
|
break;
|
2014-12-02 10:13:09 +08:00
|
|
|
}
|
2011-11-12 05:55:48 +08:00
|
|
|
}
|
2013-12-17 18:31:37 +08:00
|
|
|
|
2017-06-02 09:55:39 +08:00
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
else {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
|
|
|
|
Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
|
|
|
|
HadError = true;
|
|
|
|
}
|
2011-12-09 03:11:24 +08:00
|
|
|
}
|
2017-06-02 09:55:39 +08:00
|
|
|
|
2018-06-01 09:26:18 +08:00
|
|
|
bool NeedsFramework = false;
|
|
|
|
Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework);
|
|
|
|
|
|
|
|
if (NeedsFramework && ActiveModule)
|
|
|
|
Diags.Report(CurrModuleDeclLoc, diag::note_mmap_add_framework_keyword)
|
|
|
|
<< ActiveModule->getFullModuleName()
|
|
|
|
<< FixItHint::CreateReplacement(CurrModuleDeclLoc, "framework module");
|
2011-12-09 03:11:24 +08:00
|
|
|
}
|
|
|
|
|
2015-08-14 01:30:07 +08:00
|
|
|
static int compareModuleHeaders(const Module::Header *A,
|
|
|
|
const Module::Header *B) {
|
|
|
|
return A->NameAsWritten.compare(B->NameAsWritten);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse an umbrella directory declaration.
|
2011-12-09 03:11:24 +08:00
|
|
|
///
|
|
|
|
/// umbrella-dir-declaration:
|
|
|
|
/// umbrella string-literal
|
|
|
|
void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
|
|
|
|
// Parse the directory name.
|
|
|
|
if (!Tok.is(MMToken::StringLiteral)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header)
|
2011-12-09 03:11:24 +08:00
|
|
|
<< "umbrella";
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string DirName = Tok.getString();
|
|
|
|
SourceLocation DirNameLoc = consumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-09 03:11:24 +08:00
|
|
|
// Check whether we already have an umbrella.
|
|
|
|
if (ActiveModule->Umbrella) {
|
|
|
|
Diags.Report(DirNameLoc, diag::err_mmap_umbrella_clash)
|
|
|
|
<< ActiveModule->getFullModuleName();
|
2011-11-12 05:55:48 +08:00
|
|
|
HadError = true;
|
2011-12-09 03:11:24 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look for this file.
|
2014-05-18 07:10:59 +08:00
|
|
|
const DirectoryEntry *Dir = nullptr;
|
2019-08-02 05:31:56 +08:00
|
|
|
if (llvm::sys::path::is_absolute(DirName)) {
|
|
|
|
if (auto D = SourceMgr.getFileManager().getDirectory(DirName))
|
|
|
|
Dir = *D;
|
|
|
|
} else {
|
2012-02-05 10:13:05 +08:00
|
|
|
SmallString<128> PathName;
|
2011-12-09 03:11:24 +08:00
|
|
|
PathName = Directory->getName();
|
|
|
|
llvm::sys::path::append(PathName, DirName);
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto D = SourceMgr.getFileManager().getDirectory(PathName))
|
|
|
|
Dir = *D;
|
2011-11-12 05:55:48 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-09 03:11:24 +08:00
|
|
|
if (!Dir) {
|
2017-04-19 04:57:29 +08:00
|
|
|
Diags.Report(DirNameLoc, diag::warn_mmap_umbrella_dir_not_found)
|
2011-12-09 03:11:24 +08:00
|
|
|
<< DirName;
|
|
|
|
return;
|
|
|
|
}
|
2015-08-14 01:13:33 +08:00
|
|
|
|
|
|
|
if (UsesRequiresExcludedHack.count(ActiveModule)) {
|
|
|
|
// Mark this header 'textual' (see doc comment for
|
|
|
|
// ModuleMapParser::UsesRequiresExcludedHack). Although iterating over the
|
|
|
|
// directory is relatively expensive, in practice this only applies to the
|
|
|
|
// uncommonly used Tcl module on Darwin platforms.
|
|
|
|
std::error_code EC;
|
|
|
|
SmallVector<Module::Header, 6> Headers;
|
2018-10-10 21:27:25 +08:00
|
|
|
llvm::vfs::FileSystem &FS =
|
2019-03-27 06:32:06 +08:00
|
|
|
SourceMgr.getFileManager().getVirtualFileSystem();
|
2018-10-10 21:27:25 +08:00
|
|
|
for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E;
|
2015-08-14 01:13:33 +08:00
|
|
|
I != E && !EC; I.increment(EC)) {
|
2019-08-02 05:31:56 +08:00
|
|
|
if (auto FE = SourceMgr.getFileManager().getFile(I->path())) {
|
2015-08-14 01:13:33 +08:00
|
|
|
|
2019-08-02 05:31:56 +08:00
|
|
|
Module::Header Header = {I->path(), *FE};
|
2015-08-14 01:13:33 +08:00
|
|
|
Headers.push_back(std::move(Header));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort header paths so that the pcm doesn't depend on iteration order.
|
2015-08-14 01:30:07 +08:00
|
|
|
llvm::array_pod_sort(Headers.begin(), Headers.end(), compareModuleHeaders);
|
|
|
|
|
2015-08-14 01:13:33 +08:00
|
|
|
for (auto &Header : Headers)
|
|
|
|
Map.addHeader(ActiveModule, std::move(Header), ModuleMap::TextualHeader);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-12-09 03:11:24 +08:00
|
|
|
if (Module *OwningModule = Map.UmbrellaDirs[Dir]) {
|
|
|
|
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
|
|
|
|
<< OwningModule->getFullModuleName();
|
|
|
|
HadError = true;
|
|
|
|
return;
|
2015-08-14 01:13:33 +08:00
|
|
|
}
|
|
|
|
|
2011-12-09 03:11:24 +08:00
|
|
|
// Record this umbrella directory.
|
2015-05-16 10:28:53 +08:00
|
|
|
Map.setUmbrellaDir(ActiveModule, Dir, DirName);
|
2011-11-12 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a module export declaration.
|
2011-12-02 09:47:07 +08:00
|
|
|
///
|
|
|
|
/// export-declaration:
|
|
|
|
/// 'export' wildcard-module-id
|
|
|
|
///
|
|
|
|
/// wildcard-module-id:
|
|
|
|
/// identifier
|
|
|
|
/// '*'
|
|
|
|
/// identifier '.' wildcard-module-id
|
|
|
|
void ModuleMapParser::parseExportDecl() {
|
|
|
|
assert(Tok.is(MMToken::ExportKeyword));
|
|
|
|
SourceLocation ExportLoc = consumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
// Parse the module-id with an optional wildcard at the end.
|
|
|
|
ModuleId ParsedModuleId;
|
|
|
|
bool Wildcard = false;
|
|
|
|
do {
|
2014-10-23 07:50:56 +08:00
|
|
|
// FIXME: Support string-literal module names here.
|
2011-12-02 09:47:07 +08:00
|
|
|
if (Tok.is(MMToken::Identifier)) {
|
2018-07-31 03:24:48 +08:00
|
|
|
ParsedModuleId.push_back(std::make_pair(Tok.getString(),
|
2011-12-02 09:47:07 +08:00
|
|
|
Tok.getLocation()));
|
|
|
|
consumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
if (Tok.is(MMToken::Period)) {
|
|
|
|
consumeToken();
|
|
|
|
continue;
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-02 09:47:07 +08:00
|
|
|
if(Tok.is(MMToken::Star)) {
|
|
|
|
Wildcard = true;
|
2011-12-06 01:28:06 +08:00
|
|
|
consumeToken();
|
2011-12-02 09:47:07 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-09-24 17:14:14 +08:00
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
|
2011-12-02 09:47:07 +08:00
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
} while (true);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
Module::UnresolvedExportDecl Unresolved = {
|
|
|
|
ExportLoc, ParsedModuleId, Wildcard
|
2011-12-02 09:47:07 +08:00
|
|
|
};
|
|
|
|
ActiveModule->UnresolvedExports.push_back(Unresolved);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a module export_as declaration.
|
2017-09-15 07:38:44 +08:00
|
|
|
///
|
|
|
|
/// export-as-declaration:
|
|
|
|
/// 'export_as' identifier
|
|
|
|
void ModuleMapParser::parseExportAsDecl() {
|
|
|
|
assert(Tok.is(MMToken::ExportAsKeyword));
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
if (!Tok.is(MMToken::Identifier)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_module_id);
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ActiveModule->Parent) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_submodule_export_as);
|
|
|
|
consumeToken();
|
|
|
|
return;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2017-09-15 07:38:44 +08:00
|
|
|
if (!ActiveModule->ExportAsModule.empty()) {
|
|
|
|
if (ActiveModule->ExportAsModule == Tok.getString()) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::warn_mmap_redundant_export_as)
|
|
|
|
<< ActiveModule->Name << Tok.getString();
|
|
|
|
} else {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_conflicting_export_as)
|
|
|
|
<< ActiveModule->Name << ActiveModule->ExportAsModule
|
|
|
|
<< Tok.getString();
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2017-09-15 07:38:44 +08:00
|
|
|
ActiveModule->ExportAsModule = Tok.getString();
|
2018-04-17 03:42:32 +08:00
|
|
|
Map.addLinkAsDependency(ActiveModule);
|
|
|
|
|
2017-09-15 07:38:44 +08:00
|
|
|
consumeToken();
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a module use declaration.
|
2013-09-24 17:14:14 +08:00
|
|
|
///
|
2015-03-27 06:10:01 +08:00
|
|
|
/// use-declaration:
|
|
|
|
/// 'use' wildcard-module-id
|
2013-09-24 17:14:14 +08:00
|
|
|
void ModuleMapParser::parseUseDecl() {
|
|
|
|
assert(Tok.is(MMToken::UseKeyword));
|
2015-03-27 06:10:01 +08:00
|
|
|
auto KWLoc = consumeToken();
|
2013-09-24 17:14:14 +08:00
|
|
|
// Parse the module-id.
|
|
|
|
ModuleId ParsedModuleId;
|
2013-12-06 17:25:54 +08:00
|
|
|
parseModuleId(ParsedModuleId);
|
2013-09-24 17:14:14 +08:00
|
|
|
|
2015-03-27 06:10:01 +08:00
|
|
|
if (ActiveModule->Parent)
|
|
|
|
Diags.Report(KWLoc, diag::err_mmap_use_decl_submodule);
|
|
|
|
else
|
|
|
|
ActiveModule->UnresolvedDirectUses.push_back(ParsedModuleId);
|
2013-09-24 17:14:14 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a link declaration.
|
2013-01-15 01:21:00 +08:00
|
|
|
///
|
|
|
|
/// module-declaration:
|
|
|
|
/// 'link' 'framework'[opt] string-literal
|
|
|
|
void ModuleMapParser::parseLinkDecl() {
|
|
|
|
assert(Tok.is(MMToken::LinkKeyword));
|
|
|
|
SourceLocation LinkLoc = consumeToken();
|
|
|
|
|
|
|
|
// Parse the optional 'framework' keyword.
|
|
|
|
bool IsFramework = false;
|
|
|
|
if (Tok.is(MMToken::FrameworkKeyword)) {
|
|
|
|
consumeToken();
|
|
|
|
IsFramework = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the library name
|
|
|
|
if (!Tok.is(MMToken::StringLiteral)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name)
|
|
|
|
<< IsFramework << SourceRange(LinkLoc);
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string LibraryName = Tok.getString();
|
|
|
|
consumeToken();
|
|
|
|
ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName,
|
|
|
|
IsFramework));
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a configuration macro declaration.
|
2013-03-20 08:22:05 +08:00
|
|
|
///
|
|
|
|
/// module-declaration:
|
|
|
|
/// 'config_macros' attributes[opt] config-macro-list?
|
|
|
|
///
|
|
|
|
/// config-macro-list:
|
|
|
|
/// identifier (',' identifier)?
|
|
|
|
void ModuleMapParser::parseConfigMacros() {
|
|
|
|
assert(Tok.is(MMToken::ConfigMacros));
|
|
|
|
SourceLocation ConfigMacrosLoc = consumeToken();
|
|
|
|
|
|
|
|
// Only top-level modules can have configuration macros.
|
|
|
|
if (ActiveModule->Parent) {
|
|
|
|
Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the optional attributes.
|
|
|
|
Attributes Attrs;
|
2016-03-06 12:20:05 +08:00
|
|
|
if (parseOptionalAttributes(Attrs))
|
|
|
|
return;
|
|
|
|
|
2013-03-20 08:22:05 +08:00
|
|
|
if (Attrs.IsExhaustive && !ActiveModule->Parent) {
|
|
|
|
ActiveModule->ConfigMacrosExhaustive = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we don't have an identifier, we're done.
|
2014-10-23 07:50:56 +08:00
|
|
|
// FIXME: Support macros with the same name as a keyword here.
|
2013-03-20 08:22:05 +08:00
|
|
|
if (!Tok.is(MMToken::Identifier))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Consume the first identifier.
|
|
|
|
if (!ActiveModule->Parent) {
|
|
|
|
ActiveModule->ConfigMacros.push_back(Tok.getString().str());
|
|
|
|
}
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
do {
|
|
|
|
// If there's a comma, consume it.
|
|
|
|
if (!Tok.is(MMToken::Comma))
|
|
|
|
break;
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
// We expect to see a macro name here.
|
2014-10-23 07:50:56 +08:00
|
|
|
// FIXME: Support macros with the same name as a keyword here.
|
2013-03-20 08:22:05 +08:00
|
|
|
if (!Tok.is(MMToken::Identifier)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the macro name.
|
|
|
|
if (!ActiveModule->Parent) {
|
|
|
|
ActiveModule->ConfigMacros.push_back(Tok.getString().str());
|
|
|
|
}
|
|
|
|
consumeToken();
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Format a module-id into a string.
|
2013-03-21 05:10:35 +08:00
|
|
|
static std::string formatModuleId(const ModuleId &Id) {
|
|
|
|
std::string result;
|
|
|
|
{
|
|
|
|
llvm::raw_string_ostream OS(result);
|
|
|
|
|
|
|
|
for (unsigned I = 0, N = Id.size(); I != N; ++I) {
|
|
|
|
if (I)
|
|
|
|
OS << ".";
|
|
|
|
OS << Id[I].first;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a conflict declaration.
|
2013-03-21 05:10:35 +08:00
|
|
|
///
|
|
|
|
/// module-declaration:
|
|
|
|
/// 'conflict' module-id ',' string-literal
|
|
|
|
void ModuleMapParser::parseConflict() {
|
|
|
|
assert(Tok.is(MMToken::Conflict));
|
|
|
|
SourceLocation ConflictLoc = consumeToken();
|
|
|
|
Module::UnresolvedConflict Conflict;
|
|
|
|
|
|
|
|
// Parse the module-id.
|
|
|
|
if (parseModuleId(Conflict.Id))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Parse the ','.
|
|
|
|
if (!Tok.is(MMToken::Comma)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)
|
|
|
|
<< SourceRange(ConflictLoc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
// Parse the message.
|
|
|
|
if (!Tok.is(MMToken::StringLiteral)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)
|
|
|
|
<< formatModuleId(Conflict.Id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Conflict.Message = Tok.getString().str();
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
// Add this unresolved conflict.
|
|
|
|
ActiveModule->UnresolvedConflicts.push_back(Conflict);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse an inferred module declaration (wildcard modules).
|
2012-11-07 03:39:40 +08:00
|
|
|
///
|
|
|
|
/// module-declaration:
|
|
|
|
/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt]
|
|
|
|
/// { inferred-module-member* }
|
|
|
|
///
|
|
|
|
/// inferred-module-member:
|
|
|
|
/// 'export' '*'
|
|
|
|
/// 'exclude' identifier
|
|
|
|
void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
|
2011-12-06 06:27:44 +08:00
|
|
|
assert(Tok.is(MMToken::Star));
|
|
|
|
SourceLocation StarLoc = consumeToken();
|
|
|
|
bool Failed = false;
|
2012-11-07 03:39:40 +08:00
|
|
|
|
2011-12-06 06:27:44 +08:00
|
|
|
// Inferred modules must be submodules.
|
2012-11-07 03:39:40 +08:00
|
|
|
if (!ActiveModule && !Framework) {
|
2011-12-06 06:27:44 +08:00
|
|
|
Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule);
|
|
|
|
Failed = true;
|
|
|
|
}
|
2012-11-07 03:39:40 +08:00
|
|
|
|
|
|
|
if (ActiveModule) {
|
|
|
|
// Inferred modules must have umbrella directories.
|
2014-04-22 03:49:57 +08:00
|
|
|
if (!Failed && ActiveModule->IsAvailable &&
|
|
|
|
!ActiveModule->getUmbrellaDir()) {
|
2012-11-07 03:39:40 +08:00
|
|
|
Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
|
|
|
|
Failed = true;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-11-07 03:39:40 +08:00
|
|
|
// Check for redefinition of an inferred module.
|
|
|
|
if (!Failed && ActiveModule->InferSubmodules) {
|
|
|
|
Diags.Report(StarLoc, diag::err_mmap_inferred_redef);
|
|
|
|
if (ActiveModule->InferredSubmoduleLoc.isValid())
|
|
|
|
Diags.Report(ActiveModule->InferredSubmoduleLoc,
|
|
|
|
diag::note_mmap_prev_definition);
|
|
|
|
Failed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for the 'framework' keyword, which is not permitted here.
|
|
|
|
if (Framework) {
|
|
|
|
Diags.Report(StarLoc, diag::err_mmap_inferred_framework_submodule);
|
|
|
|
Framework = false;
|
|
|
|
}
|
|
|
|
} else if (Explicit) {
|
|
|
|
Diags.Report(StarLoc, diag::err_mmap_explicit_inferred_framework);
|
|
|
|
Explicit = false;
|
2011-12-06 06:27:44 +08:00
|
|
|
}
|
2012-11-07 03:39:40 +08:00
|
|
|
|
2011-12-06 06:27:44 +08:00
|
|
|
// If there were any problems with this inferred submodule, skip its body.
|
|
|
|
if (Failed) {
|
|
|
|
if (Tok.is(MMToken::LBrace)) {
|
|
|
|
consumeToken();
|
|
|
|
skipUntil(MMToken::RBrace);
|
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
}
|
|
|
|
HadError = true;
|
|
|
|
return;
|
|
|
|
}
|
2012-11-07 03:39:40 +08:00
|
|
|
|
|
|
|
// Parse optional attributes.
|
2012-12-21 03:22:21 +08:00
|
|
|
Attributes Attrs;
|
2016-03-06 12:20:05 +08:00
|
|
|
if (parseOptionalAttributes(Attrs))
|
|
|
|
return;
|
2012-11-07 03:39:40 +08:00
|
|
|
|
|
|
|
if (ActiveModule) {
|
|
|
|
// Note that we have an inferred submodule.
|
|
|
|
ActiveModule->InferSubmodules = true;
|
|
|
|
ActiveModule->InferredSubmoduleLoc = StarLoc;
|
|
|
|
ActiveModule->InferExplicitSubmodules = Explicit;
|
|
|
|
} else {
|
|
|
|
// We'll be inferring framework modules for this directory.
|
|
|
|
Map.InferredDirectories[Directory].InferModules = true;
|
2015-01-14 01:47:44 +08:00
|
|
|
Map.InferredDirectories[Directory].Attrs = Attrs;
|
2014-04-15 02:00:01 +08:00
|
|
|
Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile;
|
2014-03-07 05:59:38 +08:00
|
|
|
// FIXME: Handle the 'framework' keyword.
|
2012-11-07 03:39:40 +08:00
|
|
|
}
|
|
|
|
|
2011-12-06 06:27:44 +08:00
|
|
|
// Parse the opening brace.
|
|
|
|
if (!Tok.is(MMToken::LBrace)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard);
|
|
|
|
HadError = true;
|
|
|
|
return;
|
2018-07-31 03:24:48 +08:00
|
|
|
}
|
2011-12-06 06:27:44 +08:00
|
|
|
SourceLocation LBraceLoc = consumeToken();
|
|
|
|
|
|
|
|
// Parse the body of the inferred submodule.
|
|
|
|
bool Done = false;
|
|
|
|
do {
|
|
|
|
switch (Tok.Kind) {
|
|
|
|
case MMToken::EndOfFile:
|
|
|
|
case MMToken::RBrace:
|
|
|
|
Done = true;
|
|
|
|
break;
|
2012-11-07 03:39:40 +08:00
|
|
|
|
2017-12-07 07:18:41 +08:00
|
|
|
case MMToken::ExcludeKeyword:
|
2012-11-07 03:39:40 +08:00
|
|
|
if (ActiveModule) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
|
2014-05-18 07:10:59 +08:00
|
|
|
<< (ActiveModule != nullptr);
|
2012-11-07 03:39:40 +08:00
|
|
|
consumeToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
consumeToken();
|
2014-10-23 07:50:56 +08:00
|
|
|
// FIXME: Support string-literal module names here.
|
2012-11-07 03:39:40 +08:00
|
|
|
if (!Tok.is(MMToken::Identifier)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Map.InferredDirectories[Directory].ExcludedModules
|
|
|
|
.push_back(Tok.getString());
|
|
|
|
consumeToken();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MMToken::ExportKeyword:
|
|
|
|
if (!ActiveModule) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
|
2014-05-18 07:10:59 +08:00
|
|
|
<< (ActiveModule != nullptr);
|
2012-11-07 03:39:40 +08:00
|
|
|
consumeToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-12-06 06:27:44 +08:00
|
|
|
consumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
if (Tok.is(MMToken::Star))
|
2011-12-07 01:34:58 +08:00
|
|
|
ActiveModule->InferExportWildcard = true;
|
2011-12-06 06:27:44 +08:00
|
|
|
else
|
2018-07-31 03:24:48 +08:00
|
|
|
Diags.Report(Tok.getLocation(),
|
2011-12-06 06:27:44 +08:00
|
|
|
diag::err_mmap_expected_export_wildcard);
|
|
|
|
consumeToken();
|
|
|
|
break;
|
2012-11-07 03:39:40 +08:00
|
|
|
|
2011-12-06 06:27:44 +08:00
|
|
|
case MMToken::ExplicitKeyword:
|
|
|
|
case MMToken::ModuleKeyword:
|
|
|
|
case MMToken::HeaderKeyword:
|
2013-06-21 05:14:14 +08:00
|
|
|
case MMToken::PrivateKeyword:
|
2011-12-06 06:27:44 +08:00
|
|
|
case MMToken::UmbrellaKeyword:
|
|
|
|
default:
|
2012-11-07 03:39:40 +08:00
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member)
|
2014-05-18 07:10:59 +08:00
|
|
|
<< (ActiveModule != nullptr);
|
2011-12-06 06:27:44 +08:00
|
|
|
consumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
break;
|
2011-12-06 06:27:44 +08:00
|
|
|
}
|
|
|
|
} while (!Done);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-06 06:27:44 +08:00
|
|
|
if (Tok.is(MMToken::RBrace))
|
|
|
|
consumeToken();
|
|
|
|
else {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rbrace);
|
|
|
|
Diags.Report(LBraceLoc, diag::note_mmap_lbrace_match);
|
|
|
|
HadError = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse optional attributes.
|
2012-11-07 03:39:40 +08:00
|
|
|
///
|
|
|
|
/// attributes:
|
|
|
|
/// attribute attributes
|
|
|
|
/// attribute
|
|
|
|
///
|
|
|
|
/// attribute:
|
|
|
|
/// [ identifier ]
|
|
|
|
///
|
|
|
|
/// \param Attrs Will be filled in with the parsed attributes.
|
|
|
|
///
|
|
|
|
/// \returns true if an error occurred, false otherwise.
|
2012-12-21 03:22:21 +08:00
|
|
|
bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
|
2012-11-07 03:39:40 +08:00
|
|
|
bool HadError = false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-11-07 03:39:40 +08:00
|
|
|
while (Tok.is(MMToken::LSquare)) {
|
|
|
|
// Consume the '['.
|
|
|
|
SourceLocation LSquareLoc = consumeToken();
|
|
|
|
|
|
|
|
// Check whether we have an attribute name here.
|
|
|
|
if (!Tok.is(MMToken::Identifier)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute);
|
|
|
|
skipUntil(MMToken::RSquare);
|
|
|
|
if (Tok.is(MMToken::RSquare))
|
|
|
|
consumeToken();
|
|
|
|
HadError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode the attribute name.
|
|
|
|
AttributeKind Attribute
|
|
|
|
= llvm::StringSwitch<AttributeKind>(Tok.getString())
|
2013-03-20 08:22:05 +08:00
|
|
|
.Case("exhaustive", AT_exhaustive)
|
2014-03-02 13:58:18 +08:00
|
|
|
.Case("extern_c", AT_extern_c)
|
2016-10-21 09:41:56 +08:00
|
|
|
.Case("no_undeclared_includes", AT_no_undeclared_includes)
|
2012-11-07 03:39:40 +08:00
|
|
|
.Case("system", AT_system)
|
|
|
|
.Default(AT_unknown);
|
|
|
|
switch (Attribute) {
|
|
|
|
case AT_unknown:
|
|
|
|
Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute)
|
|
|
|
<< Tok.getString();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AT_system:
|
|
|
|
Attrs.IsSystem = true;
|
|
|
|
break;
|
2013-03-20 08:22:05 +08:00
|
|
|
|
2014-03-02 13:58:18 +08:00
|
|
|
case AT_extern_c:
|
|
|
|
Attrs.IsExternC = true;
|
|
|
|
break;
|
|
|
|
|
2013-03-20 08:22:05 +08:00
|
|
|
case AT_exhaustive:
|
|
|
|
Attrs.IsExhaustive = true;
|
|
|
|
break;
|
2016-10-21 09:41:56 +08:00
|
|
|
|
|
|
|
case AT_no_undeclared_includes:
|
|
|
|
Attrs.NoUndeclaredIncludes = true;
|
|
|
|
break;
|
2012-11-07 03:39:40 +08:00
|
|
|
}
|
|
|
|
consumeToken();
|
|
|
|
|
|
|
|
// Consume the ']'.
|
|
|
|
if (!Tok.is(MMToken::RSquare)) {
|
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare);
|
|
|
|
Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match);
|
|
|
|
skipUntil(MMToken::RSquare);
|
|
|
|
HadError = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(MMToken::RSquare))
|
|
|
|
consumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
return HadError;
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a module map file.
|
2011-11-12 03:10:28 +08:00
|
|
|
///
|
|
|
|
/// module-map-file:
|
|
|
|
/// module-declaration*
|
|
|
|
bool ModuleMapParser::parseModuleMapFile() {
|
|
|
|
do {
|
|
|
|
switch (Tok.Kind) {
|
|
|
|
case MMToken::EndOfFile:
|
|
|
|
return HadError;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-12-07 10:23:45 +08:00
|
|
|
case MMToken::ExplicitKeyword:
|
2013-09-11 15:20:44 +08:00
|
|
|
case MMToken::ExternKeyword:
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::ModuleKeyword:
|
2011-11-18 06:09:43 +08:00
|
|
|
case MMToken::FrameworkKeyword:
|
2011-11-12 03:10:28 +08:00
|
|
|
parseModuleDecl();
|
|
|
|
break;
|
2013-01-15 01:21:00 +08:00
|
|
|
|
2011-12-31 12:05:44 +08:00
|
|
|
case MMToken::Comma:
|
2013-03-20 08:22:05 +08:00
|
|
|
case MMToken::ConfigMacros:
|
2013-03-21 05:10:35 +08:00
|
|
|
case MMToken::Conflict:
|
2013-10-29 06:18:19 +08:00
|
|
|
case MMToken::Exclaim:
|
2012-10-15 14:28:11 +08:00
|
|
|
case MMToken::ExcludeKeyword:
|
2011-12-02 09:47:07 +08:00
|
|
|
case MMToken::ExportKeyword:
|
2017-09-15 07:38:44 +08:00
|
|
|
case MMToken::ExportAsKeyword:
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::HeaderKeyword:
|
|
|
|
case MMToken::Identifier:
|
|
|
|
case MMToken::LBrace:
|
2013-01-15 01:21:00 +08:00
|
|
|
case MMToken::LinkKeyword:
|
2012-01-28 03:52:33 +08:00
|
|
|
case MMToken::LSquare:
|
2011-12-02 09:47:07 +08:00
|
|
|
case MMToken::Period:
|
2013-06-21 05:14:14 +08:00
|
|
|
case MMToken::PrivateKeyword:
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::RBrace:
|
2012-01-28 03:52:33 +08:00
|
|
|
case MMToken::RSquare:
|
2011-12-31 12:05:44 +08:00
|
|
|
case MMToken::RequiresKeyword:
|
2011-12-02 09:47:07 +08:00
|
|
|
case MMToken::Star:
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::StringLiteral:
|
2017-06-02 09:55:39 +08:00
|
|
|
case MMToken::IntegerLiteral:
|
2014-10-23 09:03:45 +08:00
|
|
|
case MMToken::TextualKeyword:
|
2011-11-12 03:10:28 +08:00
|
|
|
case MMToken::UmbrellaKeyword:
|
2013-09-24 17:14:14 +08:00
|
|
|
case MMToken::UseKeyword:
|
2011-11-12 03:10:28 +08:00
|
|
|
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_module);
|
|
|
|
HadError = true;
|
|
|
|
consumeToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
|
2014-12-10 11:09:48 +08:00
|
|
|
bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
|
2018-01-06 06:13:56 +08:00
|
|
|
const DirectoryEntry *Dir, FileID ID,
|
2017-05-06 06:18:51 +08:00
|
|
|
unsigned *Offset,
|
2015-07-14 10:06:01 +08:00
|
|
|
SourceLocation ExternModuleLoc) {
|
2017-05-06 06:18:51 +08:00
|
|
|
assert(Target && "Missing target information");
|
2013-01-10 09:43:00 +08:00
|
|
|
llvm::DenseMap<const FileEntry *, bool>::iterator Known
|
|
|
|
= ParsedModuleMap.find(File);
|
|
|
|
if (Known != ParsedModuleMap.end())
|
|
|
|
return Known->second;
|
|
|
|
|
2017-05-06 06:18:51 +08:00
|
|
|
// If the module map file wasn't already entered, do so now.
|
|
|
|
if (ID.isInvalid()) {
|
2017-06-29 10:19:42 +08:00
|
|
|
auto FileCharacter =
|
|
|
|
IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap;
|
2017-05-06 06:18:51 +08:00
|
|
|
ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter);
|
|
|
|
}
|
|
|
|
|
2014-05-18 07:10:59 +08:00
|
|
|
assert(Target && "Missing target information");
|
Use the same SourceManager for ModuleMaps and compilations.
This allows using virtual file mappings on the original SourceManager to
map in virtual module.map files. Without this patch, the ModuleMap
search will find a module.map file (as the FileEntry exists in the
FileManager), but will be unable to get the content from the
SourceManager (as ModuleMap previously created its own SourceManager).
Two problems needed to be fixed which this patch exposed:
1. Storing the inferred module map
When writing out a module, the ASTWriter stores the names of the files
in the main source manager; when loading the AST again, the ASTReader
errs out if such a file is found missing, unless it is overridden.
Previously CompilerInstance's compileModule method would store the
inferred module map to a temporary file; the problem with this approach
is that now that the module map is handled by the main source manager,
the ASTWriter stores the name of the temporary module map as source to
the compilation; later, when the module is loaded, the temporary file
has already been deleted, which leads to a compilation error. This patch
changes the inferred module map to instead inject a virtual file into
the source manager. This both saves some disk IO, and works with how the
ASTWriter/ASTReader handle overridden source files.
2. Changing test input in test/Modules/Inputs/*
Now that the module map file is handled by the main source manager, the
VerifyDiagnosticConsumer will not ignore diagnostics created while
parsing the module map file. The module test test/Modules/renamed.m uses
-I test/Modules/Inputs and triggers recursive loading of all module maps
in test/Modules/Inputs, some of which had conflicting names, thus
leading errors while parsing the module maps. Those diagnostics already
occur on trunk, but before this patch they would not break the test, as
they were ignored by the VerifyDiagnosticConsumer. This patch thus
changes the module maps that have been recently introduced which broke
the invariant of compatible modules maps in test/Modules/Inputs.
llvm-svn: 193314
2013-10-24 15:51:24 +08:00
|
|
|
const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
|
2011-11-12 03:10:28 +08:00
|
|
|
if (!Buffer)
|
2013-01-10 09:43:00 +08:00
|
|
|
return ParsedModuleMap[File] = true;
|
2017-05-06 06:18:51 +08:00
|
|
|
assert((!Offset || *Offset <= Buffer->getBufferSize()) &&
|
|
|
|
"invalid buffer offset");
|
2014-03-20 04:23:34 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
// Parse this module map file.
|
2017-05-06 06:18:51 +08:00
|
|
|
Lexer L(SourceMgr.getLocForStartOfFile(ID), MMapLangOpts,
|
|
|
|
Buffer->getBufferStart(),
|
|
|
|
Buffer->getBufferStart() + (Offset ? *Offset : 0),
|
|
|
|
Buffer->getBufferEnd());
|
2015-08-09 12:46:57 +08:00
|
|
|
SourceLocation Start = L.getSourceLocation();
|
2014-04-15 02:00:01 +08:00
|
|
|
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
|
2018-01-06 06:13:56 +08:00
|
|
|
IsSystem);
|
2011-11-12 03:10:28 +08:00
|
|
|
bool Result = Parser.parseModuleMapFile();
|
2013-01-10 09:43:00 +08:00
|
|
|
ParsedModuleMap[File] = Result;
|
2015-08-09 12:46:57 +08:00
|
|
|
|
2017-05-06 06:18:51 +08:00
|
|
|
if (Offset) {
|
|
|
|
auto Loc = SourceMgr.getDecomposedLoc(Parser.getLocation());
|
|
|
|
assert(Loc.first == ID && "stopped in a different file?");
|
|
|
|
*Offset = Loc.second;
|
|
|
|
}
|
|
|
|
|
2015-08-09 12:46:57 +08:00
|
|
|
// Notify callbacks that we parsed it.
|
|
|
|
for (const auto &Cb : Callbacks)
|
|
|
|
Cb->moduleMapFileRead(Start, *File, IsSystem);
|
2018-01-05 10:33:18 +08:00
|
|
|
|
2011-11-12 03:10:28 +08:00
|
|
|
return Result;
|
|
|
|
}
|