aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-08-26 23:56:07 +0000
committerDouglas Gregor <dgregor@apple.com>2011-08-26 23:56:07 +0000
commit6aa52ec6b969faabf3764baf79d89810b8249a7e (patch)
treed0921823c1cb331fe29e8cb31b78e9719e2126fb
parentd37c67b8f26ffe31e7f7292f26ab39cee78151d8 (diff)
Introduce support for a simple module import declaration, which
loads the named module. The syntax itself is intentionally hideous and will be replaced at some later point with something more palatable. For now, we're focusing on the semantics: - Module imports are handled first by the preprocessor (to get macro definitions) and then the same tokens are also handled by the parser (to get declarations). If both happen (as in normal compilation), the second one is redundant, because we currently have no way to hide macros or declarations when loading a module. Chris gets credit for this mad-but-workable scheme. - The Preprocessor now holds on to a reference to a module loader, which is responsible for loading named modules. CompilerInstance is the only important module loader: it now knows how to create and wire up an AST reader on demand to actually perform the module load. - We search for modules in the include path, using the module name with the suffix ".pcm" (precompiled module) for the file name. This is a temporary hack; we hope to improve the situation in the future. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138679 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td3
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td6
-rw-r--r--include/clang/Basic/IdentifierTable.h2
-rw-r--r--include/clang/Basic/TokenKinds.def1
-rw-r--r--include/clang/Frontend/ASTUnit.h10
-rw-r--r--include/clang/Frontend/CompilerInstance.h21
-rw-r--r--include/clang/Lex/ModuleLoader.h55
-rw-r--r--include/clang/Lex/Preprocessor.h10
-rw-r--r--include/clang/Parse/Parser.h4
-rw-r--r--include/clang/Sema/Sema.h11
-rw-r--r--lib/Frontend/ASTUnit.cpp2
-rw-r--r--lib/Frontend/CompilerInstance.cpp112
-rw-r--r--lib/Lex/Lexer.cpp1
-rw-r--r--lib/Lex/Preprocessor.cpp38
-rw-r--r--lib/Parse/Parser.cpp24
-rw-r--r--lib/Sema/SemaDecl.cpp14
-rw-r--r--test/Misc/warning-flags.c3
-rw-r--r--test/Modules/Inputs/diamond_bottom.h3
-rw-r--r--test/Modules/Inputs/diamond_left.h2
-rw-r--r--test/Modules/Inputs/diamond_right.h2
-rw-r--r--test/Modules/Inputs/load_failure.h1
-rw-r--r--test/Modules/diamond.c16
-rw-r--r--test/Modules/load_failure.c17
-rw-r--r--test/Modules/lookup.cpp14
-rw-r--r--test/Modules/lookup.m10
25 files changed, 313 insertions, 69 deletions
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index 4b5de366cb..62d852572a 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -59,7 +59,8 @@ def err_friends_define_only_namespace_scope : Error<
"cannot define a function with non-namespace scope in a friend declaration">;
def err_deleted_non_function : Error<
"only functions can have deleted definitions">;
-
+def warn_module_not_found : Warning<"module '%0' not found">, DefaultFatal;
+
// Sema && Lex
def ext_longlong : Extension<
"'long long' is an extension when C99 mode is not enabled">,
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 27b4f850ee..9a6e7545b4 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -569,5 +569,11 @@ def err_seh___except_filter : Error<
def err_seh___finally_block : Error<
"%0 only allowed in __finally block">;
+// Modules
+def err_module_expected_ident : Error<
+ "expected a module name after '__import__'">;
+def err_module_expected_semi : Error<
+ "expected a semicolon name after module name">;
+
} // end of Parse Issue category.
} // end of Parser diagnostics
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 017af5caee..9238d3daa7 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -252,7 +252,7 @@ private:
void RecomputeNeedsHandleIdentifier() {
NeedsHandleIdentifier =
(isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
- isExtensionToken());
+ isExtensionToken() | getTokenID() == tok::kw___import__);
}
};
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index e0b22b7b24..ccc2e612b2 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -397,6 +397,7 @@ KEYWORD(__array_extent , KEYCXX)
// Apple Extension.
KEYWORD(__private_extern__ , KEYALL)
+KEYWORD(__import__ , KEYALL)
// Microsoft Extension.
KEYWORD(__declspec , KEYALL)
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 190ab85713..731ce383fc 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -18,6 +18,7 @@
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
@@ -66,7 +67,7 @@ class GlobalCodeCompletionAllocator
/// \brief Utility class for loading a ASTContext from an AST file.
///
-class ASTUnit {
+class ASTUnit : public ModuleLoader {
public:
typedef std::map<FileID, std::vector<PreprocessedEntity *> >
PreprocessedEntitiesByFileMap;
@@ -696,6 +697,13 @@ public:
///
/// \returns True if an error occurred, false otherwise.
bool serialize(raw_ostream &OS);
+
+ virtual ModuleKey loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) {
+ // ASTUnit doesn't know how to load modules (not that this matters).
+ return 0;
+ }
};
} // namespace clang
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 3f97f1addb..88f8976b67 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Lex/ModuleLoader.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/OwningPtr.h"
@@ -56,7 +57,7 @@ class TargetInfo;
/// in to the compiler instance for everything. When possible, utility functions
/// come in two forms; a short form that reuses the CompilerInstance objects,
/// and a long form that takes explicit instances of any required objects.
-class CompilerInstance {
+class CompilerInstance : public ModuleLoader {
/// The options used in this compiler instance.
llvm::IntrusiveRefCntPtr<CompilerInvocation> Invocation;
@@ -498,20 +499,6 @@ public:
/// and replace any existing one with it.
void createPreprocessor();
- /// Create a Preprocessor object.
- ///
- /// Note that this also creates a new HeaderSearch object which will be owned
- /// by the resulting Preprocessor.
- ///
- /// \return The new object on success, or null on failure.
- static Preprocessor *createPreprocessor(Diagnostic &, const LangOptions &,
- const PreprocessorOptions &,
- const HeaderSearchOptions &,
- const DependencyOutputOptions &,
- const TargetInfo &,
- const FrontendOptions &,
- SourceManager &, FileManager &);
-
/// Create the AST context.
void createASTContext();
@@ -626,6 +613,10 @@ public:
const FrontendOptions &Opts);
/// }
+
+ virtual ModuleKey loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc);
};
} // end namespace clang
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index e69de29bb2..72ec0e3ebc 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -0,0 +1,55 @@
+//===--- ModuleLoader.h - Module Loader Interface ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ModuleLoader interface, which is responsible for
+// loading named modules.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LEX_MODULE_LOADER_H
+#define LLVM_CLANG_LEX_MODULE_LOADER_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+class IdentifierInfo;
+
+/// \brief An opaque key that is used to describe the module and can be
+/// interpreted by the module loader itself.
+typedef void *ModuleKey;
+
+/// \brief Abstract interface for a module loader.
+///
+/// This abstract interface describes a module loader, which is responsible
+/// for resolving a module name (e.g., "std") to an actual module file, and
+/// then loading that module.
+class ModuleLoader {
+public:
+ virtual ~ModuleLoader();
+
+ /// \brief Attempt to load the given module.
+ ///
+ /// This routine attempts to load the module described by the given
+ /// parameters.
+ ///
+ /// \param ImportLoc The location of the 'import' keyword.
+ /// \param ModuleName The name of the module to be loaded.
+ /// \param ModuleNameLoc The location of the module name.
+ ///
+ /// \returns If successful, a non-NULL module key describing this module.
+ /// Otherwise, returns NULL to indicate that the module could not be
+ /// loaded.
+ virtual ModuleKey loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) = 0;
+};
+
+}
+
+#endif
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index a95645451e..1ab6411e98 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -49,6 +49,7 @@ class PPCallbacks;
class CodeCompletionHandler;
class DirectoryLookup;
class PreprocessingRecord;
+class ModuleLoader;
/// Preprocessor - This object engages in a tight little dance with the lexer to
/// efficiently preprocess tokens. Lexers know only about tokens within a
@@ -63,10 +64,12 @@ class Preprocessor : public llvm::RefCountedBase<Preprocessor> {
SourceManager &SourceMgr;
ScratchBuffer *ScratchBuf;
HeaderSearch &HeaderInfo;
+ ModuleLoader &TheModuleLoader;
/// \brief External source of macros.
ExternalPreprocessorSource *ExternalSource;
+
/// PTH - An optional PTHManager object used for getting tokens from
/// a token cache rather than lexing the original source file.
llvm::OwningPtr<PTHManager> PTH;
@@ -294,6 +297,7 @@ public:
Preprocessor(Diagnostic &diags, const LangOptions &opts,
const TargetInfo &target,
SourceManager &SM, HeaderSearch &Headers,
+ ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup = 0,
bool OwnsHeaderSearch = false);
@@ -325,6 +329,9 @@ public:
return ExternalSource;
}
+ /// \brief Retrieve the module loader associated with this preprocessor.
+ ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
+
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
@@ -1008,6 +1015,9 @@ private:
/// the macro should not be expanded return true, otherwise return false.
bool HandleMacroExpandedIdentifier(Token &Tok, MacroInfo *MI);
+ /// \brief Handle a module import directive.
+ void HandleModuleImport(Token &Import);
+
/// \brief Cache macro expanded tokens for TokenLexers.
//
/// Works like a stack; a TokenLexer adds the macro expanded tokens that is
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 1215e2daa7..e5a129beb3 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1916,6 +1916,10 @@ bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
SourceLocation &DeclEnd);
//===--------------------------------------------------------------------===//
+ // Modules
+ DeclGroupPtrTy ParseModuleImport();
+
+ //===--------------------------------------------------------------------===//
// GNU G++: Type Traits [Type-Traits.html in the GCC manual]
ExprResult ParseUnaryTypeTrait();
ExprResult ParseBinaryTypeTrait();
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index adf2702cce..2e49840d0e 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1073,6 +1073,17 @@ public:
SourceLocation AsmLoc,
SourceLocation RParenLoc);
+ /// \brief The parser has processed a module import declaration.
+ ///
+ /// \param ImportLoc The location of the '__import__' keyword.
+ ///
+ /// \param ModuleName The name of the module.
+ ///
+ /// \param ModuleNameLoc The location of the module name.
+ DeclResult ActOnModuleImport(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc);
+
/// Scope actions.
void ActOnPopScope(SourceLocation Loc, Scope *S);
void ActOnTranslationUnitScope(Scope *S);
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 4a5a29a9c9..7f25a0045e 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -616,7 +616,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->Target = TargetInfo::CreateTargetInfo(AST->getDiagnostics(),
TargetOpts);
AST->PP = new Preprocessor(AST->getDiagnostics(), LangInfo, *AST->Target,
- AST->getSourceManager(), HeaderInfo);
+ AST->getSourceManager(), HeaderInfo, *AST);
Preprocessor &PP = *AST->PP;
PP.setPredefines(Reader->getSuggestedPredefines());
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index ec8b6dc910..f53d0b064c 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -191,52 +191,38 @@ void CompilerInstance::createSourceManager(FileManager &FileMgr) {
// Preprocessor
void CompilerInstance::createPreprocessor() {
- PP = createPreprocessor(getDiagnostics(), getLangOpts(),
- getPreprocessorOpts(), getHeaderSearchOpts(),
- getDependencyOutputOpts(), getTarget(),
- getFrontendOpts(), getSourceManager(),
- getFileManager());
-}
-
-Preprocessor *
-CompilerInstance::createPreprocessor(Diagnostic &Diags,
- const LangOptions &LangInfo,
- const PreprocessorOptions &PPOpts,
- const HeaderSearchOptions &HSOpts,
- const DependencyOutputOptions &DepOpts,
- const TargetInfo &Target,
- const FrontendOptions &FEOpts,
- SourceManager &SourceMgr,
- FileManager &FileMgr) {
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+
// Create a PTH manager if we are using some form of a token cache.
PTHManager *PTHMgr = 0;
if (!PPOpts.TokenCache.empty())
- PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
-
+ PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics());
+
// Create the Preprocessor.
- HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
- Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
- SourceMgr, *HeaderInfo, PTHMgr,
- /*OwnsHeaderSearch=*/true);
-
+ HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager());
+ PP = new Preprocessor(getDiagnostics(), getLangOpts(), getTarget(),
+ getSourceManager(), *HeaderInfo, *this, PTHMgr,
+ /*OwnsHeaderSearch=*/true);
+
// Note that this is different then passing PTHMgr to Preprocessor's ctor.
// That argument is used as the IdentifierInfoLookup argument to
// IdentifierTable's ctor.
if (PTHMgr) {
- PTHMgr->setPreprocessor(PP);
+ PTHMgr->setPreprocessor(&*PP);
PP->setPTHManager(PTHMgr);
}
-
+
if (PPOpts.DetailedRecord)
PP->createPreprocessingRecord(
- PPOpts.DetailedRecordIncludesNestedMacroExpansions);
+ PPOpts.DetailedRecordIncludesNestedMacroExpansions);
+
+ InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
- InitializePreprocessor(*PP, PPOpts, HSOpts, FEOpts);
-
// Handle generating dependencies, if requested.
+ const DependencyOutputOptions &DepOpts = getDependencyOutputOpts();
if (!DepOpts.OutputFile.empty())
AttachDependencyFileGen(*PP, DepOpts);
-
+
// Handle generating header include information, if requested.
if (DepOpts.ShowHeaderIncludes)
AttachHeaderIncludeGen(*PP);
@@ -247,8 +233,6 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags,
AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath,
/*ShowDepth=*/false);
}
-
- return PP;
}
// ASTContext
@@ -640,4 +624,68 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
return !getDiagnostics().getClient()->getNumErrors();
}
+ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) {
+ // Determine what file we're searching from.
+ SourceManager &SourceMgr = getSourceManager();
+ SourceLocation ExpandedImportLoc = SourceMgr.getExpansionLoc(ImportLoc);
+ const FileEntry *CurFile
+ = SourceMgr.getFileEntryForID(SourceMgr.getFileID(ExpandedImportLoc));
+ if (!CurFile)
+ CurFile = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
+
+ // Search for a module with the given name.
+ std::string Filename = ModuleName.getName().str();
+ Filename += ".pcm";
+ const DirectoryLookup *CurDir = 0;
+ const FileEntry *ModuleFile
+ = PP->getHeaderSearchInfo().LookupFile(Filename, /*isAngled=*/false,
+ /*FromDir=*/0, CurDir, CurFile,
+ /*SearchPath=*/0,
+ /*RelativePath=*/0);
+ if (!ModuleFile) {
+ getDiagnostics().Report(ModuleNameLoc, diag::warn_module_not_found)
+ << ModuleName.getName()
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ return 0;
+ }
+
+ // If we don't already have an ASTReader, create one now.
+ if (!ModuleManager) {
+ std::string Sysroot = getHeaderSearchOpts().Sysroot;
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+ ModuleManager = new ASTReader(getPreprocessor(), &*Context,
+ Sysroot.empty() ? "" : Sysroot.c_str(),
+ PPOpts.DisablePCHValidation,
+ PPOpts.DisableStatCache);
+ ModuleManager->setDeserializationListener(
+ getASTConsumer().GetASTDeserializationListener());
+ getASTContext().setASTMutationListener(
+ getASTConsumer().GetASTMutationListener());
+ llvm::OwningPtr<ExternalASTSource> Source;
+ Source.reset(ModuleManager);
+ getASTContext().setExternalSource(Source);
+ ModuleManager->InitializeSema(getSema());
+ }
+
+ // Try to load the module we found.
+ switch (ModuleManager->ReadAST(ModuleFile->getName(),
+ serialization::MK_Module)) {
+ case ASTReader::Success:
+ break;
+
+ case ASTReader::IgnorePCH:
+ // FIXME: The ASTReader will already have complained, but can we showhorn
+ // that diagnostic information into a more useful form?
+ return 0;
+
+ case ASTReader::Failure:
+ // Already complained.
+ return 0;
+ }
+
+ // FIXME: The module file's FileEntry makes a poor key indeed!
+ return (ModuleKey)ModuleFile;
+}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 1ec50cd2c5..64b8744922 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1277,6 +1277,7 @@ FinishIdentifier:
// preprocessor, which may macro expand it or something.
if (II->isHandleIdentifierCase())
PP->HandleIdentifier(Result);
+
return;
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 24d36cdb25..1d1687d84b 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -35,6 +35,7 @@
#include "clang/Lex/ScratchBuffer.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -50,12 +51,12 @@ ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
const TargetInfo &target, SourceManager &SM,
- HeaderSearch &Headers,
+ HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
IdentifierInfoLookup* IILookup,
bool OwnsHeaders)
: Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()),
- SourceMgr(SM),
- HeaderInfo(Headers), ExternalSource(0),
+ SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
+ ExternalSource(0),
Identifiers(opts, IILookup), BuiltinInfo(Target), CodeComplete(0),
CodeCompletionFile(0), SkipMainFilePreamble(0, true), CurPPLexer(0),
CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0), MIChainHead(0),
@@ -483,7 +484,7 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
if (!DisableMacroExpansion && !Identifier.isExpandDisabled()) {
if (MI->isEnabled()) {
if (!HandleMacroExpandedIdentifier(Identifier, MI))
- return;
+ goto finish;
} else {
// C99 6.10.3.4p2 says that a disabled macro may never again be
// expanded, even if it's in a context where it could be expanded in the
@@ -505,6 +506,33 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
// like "#define TY typeof", "TY(1) x".
if (II.isExtensionToken() && !DisableMacroExpansion)
Diag(Identifier, diag::ext_token_used);
+
+finish:
+ // If we have the start of a module import, handle it now.
+ if (Identifier.is(tok::kw___import__) &&
+ !InMacroArgs && !DisableMacroExpansion)
+ HandleModuleImport(Identifier);
+}
+
+void Preprocessor::HandleModuleImport(Token &Import) {
+ // The token sequence
+ //
+ // __import__ identifier
+ //
+ // indicates a module import directive. We load the module and then
+ // leave the token sequence for the parser.
+ Token ModuleNameTok = LookAhead(0);
+ if (ModuleNameTok.getKind() != tok::identifier)
+ return;
+
+ (void)TheModuleLoader.loadModule(Import.getLocation(),
+ *ModuleNameTok.getIdentifierInfo(),
+ ModuleNameTok.getLocation());
+
+ // FIXME: Transmogrify __import__ into some kind of AST-only __import__ that
+ // is not recognized by the preprocessor but is recognized by the parser.
+ // It would also be useful to stash the ModuleKey somewhere, so we don't try
+ // to load the module twice.
}
void Preprocessor::AddCommentHandler(CommentHandler *Handler) {
@@ -535,6 +563,8 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) {
return true;
}
+ModuleLoader::~ModuleLoader() { }
+
CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 0da2b4302c..39edab1911 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -679,6 +679,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
ParseMicrosoftIfExistsExternalDeclaration();
return DeclGroupPtrTy();
+ case tok::kw___import__:
+ return ParseModuleImport();
+
default:
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
@@ -1541,3 +1544,24 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
}
ConsumeBrace();
}
+
+Parser::DeclGroupPtrTy Parser::ParseModuleImport() {
+ assert(Tok.is(tok::kw___import__) && "Improper start to module import");
+ SourceLocation ImportLoc = ConsumeToken();
+
+ // Parse the module name.
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok, diag::err_module_expected_ident);
+ SkipUntil(tok::semi);
+ return DeclGroupPtrTy();
+ }
+
+ IdentifierInfo &ModuleName = *Tok.getIdentifierInfo();
+ SourceLocation ModuleNameLoc = ConsumeToken();
+ DeclResult Import = Actions.ActOnModuleImport(ImportLoc, ModuleName, ModuleNameLoc);
+ ExpectAndConsumeSemi(diag::err_module_expected_semi);
+ if (Import.isInvalid())
+ return DeclGroupPtrTy();
+
+ return Actions.ConvertDeclToDeclGroup(Import.get());
+}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9f43aa2f05..8f08af4778 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -38,6 +38,7 @@
// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/ModuleLoader.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
#include <cstring>
@@ -9294,6 +9295,19 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
return New;
}
+DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc,
+ IdentifierInfo &ModuleName,
+ SourceLocation ModuleNameLoc) {
+ ModuleKey Module = PP.getModuleLoader().loadModule(ImportLoc,
+ ModuleName, ModuleNameLoc);
+ if (!Module)
+ return true;
+
+ // FIXME: Actually create a declaration to describe the module import.
+ (void)Module;
+ return DeclResult((Decl *)0);
+}
+
void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
SourceLocation PragmaLoc,
SourceLocation NameLoc) {
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index b89ce41032..e29fbeadf9 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -17,7 +17,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (312):
+CHECK: Warnings without flags (313):
CHECK-NEXT: auto_storage_class
CHECK-NEXT: backslash_newline_space
CHECK-NEXT: charize_microsoft_ext
@@ -230,6 +230,7 @@ CHECK-NEXT: warn_missing_case_for_condition
CHECK-NEXT: warn_missing_dependent_template_keyword
CHECK-NEXT: warn_missing_exception_specification
CHECK-NEXT: warn_missing_whitespace_after_macro_name
+CHECK-NEXT: warn_module_not_found
CHECK-NEXT: warn_multiple_method_decl
CHECK-NEXT: warn_no_constructor_for_refconst
CHECK-NEXT: warn_nonnull_pointers_only
diff --git a/test/Modules/Inputs/diamond_bottom.h b/test/Modules/Inputs/diamond_bottom.h
index 40afc9b152..6351d028fb 100644
--- a/test/Modules/Inputs/diamond_bottom.h
+++ b/test/Modules/Inputs/diamond_bottom.h
@@ -1 +1,4 @@
+__import__ diamond_left;
+__import__ diamond_right;
+
char bottom(char *x);
diff --git a/test/Modules/Inputs/diamond_left.h b/test/Modules/Inputs/diamond_left.h
index 9758b85d97..8da494ccca 100644
--- a/test/Modules/Inputs/diamond_left.h
+++ b/test/Modules/Inputs/diamond_left.h
@@ -1,3 +1,5 @@
+__import__ diamond_top;
+
float left(float *);
int top_left(char *c);
diff --git a/test/Modules/Inputs/diamond_right.h b/test/Modules/Inputs/diamond_right.h
index 9adeb6a9a8..2efa277b1a 100644
--- a/test/Modules/Inputs/diamond_right.h
+++ b/test/Modules/Inputs/diamond_right.h
@@ -1,3 +1,5 @@
+__import__ diamond_top;
+
double right(double *);
struct left_and_right {
diff --git a/test/Modules/Inputs/load_failure.h b/test/Modules/Inputs/load_failure.h
new file mode 100644
index 0000000000..5bcb44dcb3
--- /dev/null
+++ b/test/Modules/Inputs/load_failure.h
@@ -0,0 +1 @@
+int fail(int);
diff --git a/test/Modules/diamond.c b/test/Modules/diamond.c
index f9b283a9d2..94381f2033 100644
--- a/test/Modules/diamond.c
+++ b/test/Modules/diamond.c
@@ -1,4 +1,10 @@
+
+
+
// in diamond-bottom.h: expected-note{{passing argument to parameter 'x' here}}
+
+__import__ diamond_bottom;
+
void test_diamond(int i, float f, double d, char c) {
top(&i);
left(&f);
@@ -14,8 +20,8 @@ void test_diamond(int i, float f, double d, char c) {
lr.left = 17;
}
-// RUN: %clang_cc1 -emit-pch -o %t_top.h.pch %S/Inputs/diamond_top.h
-// RUN: %clang_cc1 -import-module %t_top.h.pch -emit-pch -o %t_left.h.pch %S/Inputs/diamond_left.h
-// RUN: %clang_cc1 -import-module %t_top.h.pch -emit-pch -o %t_right.h.pch %S/Inputs/diamond_right.h
-// RUN: %clang_cc1 -import-module %t_left.h.pch -import-module %t_right.h.pch -emit-pch -o %t_bottom.h.pch %S/Inputs/diamond_bottom.h
-// RUN: %clang_cc1 -import-module %t_bottom.h.pch -verify %s
+// RUN: %clang_cc1 -emit-module -o %T/diamond_top.pcm %S/Inputs/diamond_top.h
+// RUN: %clang_cc1 -I %T -emit-module -o %T/diamond_left.pcm %S/Inputs/diamond_left.h
+// RUN: %clang_cc1 -I %T -emit-module -o %T/diamond_right.pcm %S/Inputs/diamond_right.h
+// RUN: %clang_cc1 -I %T -emit-module -o %