]> granicus.if.org Git - clang/commitdiff
Introduce support for a simple module import declaration, which
authorDouglas Gregor <dgregor@apple.com>
Fri, 26 Aug 2011 23:56:07 +0000 (23:56 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 26 Aug 2011 23:56:07 +0000 (23:56 +0000)
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

25 files changed:
include/clang/Basic/DiagnosticCommonKinds.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/IdentifierTable.h
include/clang/Basic/TokenKinds.def
include/clang/Frontend/ASTUnit.h
include/clang/Frontend/CompilerInstance.h
include/clang/Lex/ModuleLoader.h
include/clang/Lex/Preprocessor.h
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/CompilerInstance.cpp
lib/Lex/Lexer.cpp
lib/Lex/Preprocessor.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaDecl.cpp
test/Misc/warning-flags.c
test/Modules/Inputs/diamond_bottom.h
test/Modules/Inputs/diamond_left.h
test/Modules/Inputs/diamond_right.h
test/Modules/Inputs/load_failure.h [new file with mode: 0644]
test/Modules/diamond.c
test/Modules/load_failure.c [new file with mode: 0644]
test/Modules/lookup.cpp
test/Modules/lookup.m

index 4b5de366cbc0c92d1304dada0cd9a5c80b21777d..62d852572a651353ede816bcb8e0bc5211d3fc03 100644 (file)
@@ -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">,
index 27b4f850eef12747d3c968cd77ae687d3286f10c..9a6e7545b4526e394fde348a66f8049d72c354c9 100644 (file)
@@ -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
index 017af5caee0bbf4c8c695724655ee04cbade0079..9238d3daa798aaba7855818d8eccaac3fce3139b 100644 (file)
@@ -252,7 +252,7 @@ private:
   void RecomputeNeedsHandleIdentifier() {
     NeedsHandleIdentifier =
       (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
-       isExtensionToken());
+       isExtensionToken() | getTokenID() == tok::kw___import__);
   }
 };
 
index e0b22b7b24a8376c57783ad7cfce4235af15bfcb..ccc2e612b231e9e5f4d626c6efa0c20b25b4ea92 100644 (file)
@@ -397,6 +397,7 @@ KEYWORD(__array_extent              , KEYCXX)
 
 // Apple Extension.
 KEYWORD(__private_extern__          , KEYALL)
+KEYWORD(__import__                  , KEYALL)
 
 // Microsoft Extension.
 KEYWORD(__declspec                  , KEYALL)
index 190ab857132bede5557c86907a55dbcc2698cd94..731ce383fc7032f1b5dea35da3011c1ec95c8348 100644 (file)
@@ -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
index 3f97f1addbc257c8f2430d1c073ce375fb916bf2..88f8976b67cbab075614f771c7abab023ba40d35 100644 (file)
@@ -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
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..72ec0e3ebc9f5d56266f927210f7b521e30207e1 100644 (file)
@@ -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
index a95645451eda0547e31fa78b265a3cfdc9d767f0..1ab6411e986d4f5c6df53015f9b3b95f04a65b0b 100644 (file)
@@ -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
index 1215e2daa7358735414259655d48627aff87f4b7..e5a129beb3cc747308296709298506d630436fd0 100644 (file)
@@ -1915,6 +1915,10 @@ bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names,
                                         SourceLocation TemplateLoc,
                                         SourceLocation &DeclEnd);
 
+  //===--------------------------------------------------------------------===//
+  // Modules
+  DeclGroupPtrTy ParseModuleImport();
+  
   //===--------------------------------------------------------------------===//
   // GNU G++: Type Traits [Type-Traits.html in the GCC manual]
   ExprResult ParseUnaryTypeTrait();
index adf2702cce8b75490b190149b393eabb48aa9f98..2e49840d0ec619aebe24eb7020972bc4545f1beb 100644 (file)
@@ -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);
index 4a5a29a9c91d745e97dba7c613b751264c055861..7f25a0045e75ad62956098018b1043308f2ede16 100644 (file)
@@ -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());
index ec8b6dc9105302c6759443ca3c14788a1787e5f0..f53d0b064cb5bdc29fc12745c972c165428e4a7b 100644 (file)
@@ -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;
+}
 
index 1ec50cd2c5d68c9d4068f4daf005bcdfeb38e195..64b87449226e8141dcae905d2cfa1529d134b546 100644 (file)
@@ -1277,6 +1277,7 @@ FinishIdentifier:
     // preprocessor, which may macro expand it or something.
     if (II->isHandleIdentifierCase())
       PP->HandleIdentifier(Result);
+    
     return;
   }
 
index 24d36cdb25810759ffa3d37b13b78e946860cbe4..1d1687d84b9ad537d46c8c0cd749bcd3bb248b5d 100644 (file)
@@ -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() { }
index 0da2b4302c49045cf05ea7522576675a2645616b..39edab191162d863c6ba8b8d70820f4b37d82b4d 100644 (file)
@@ -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());
+}
index 9f43aa2f05453b312795a61bed34c38e94f2a446..8f08af4778b464de1eaaa981ffd5f63de7a7cdcf 100644 (file)
@@ -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) {
index b89ce41032dec5db9bc5c6ceed947e5b2d840e13..e29fbeadf9a79b5c4b7e453e17beff0b0bd36433 100644 (file)
@@ -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
index 40afc9b152377a807f85ef0ce590cf777a7d26c1..6351d028fbc0f804d478e06d4b11a32d1ffb8ea3 100644 (file)
@@ -1 +1,4 @@
+__import__ diamond_left;
+__import__ diamond_right;
+
 char bottom(char *x);
index 9758b85d974125976071efe8a6eea1856bb19b6a..8da494cccad1a16e86c9c004e0564a6c1999a1d1 100644 (file)
@@ -1,3 +1,5 @@
+__import__ diamond_top;
+
 float left(float *);
 
 int top_left(char *c);
index 9adeb6a9a894e6598941ec86925b9caf37107aa9..2efa277b1a915bf82ec63a0904678c11180f6764 100644 (file)
@@ -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 (file)
index 0000000..5bcb44d
--- /dev/null
@@ -0,0 +1 @@
+int fail(int);
index f9b283a9d2407502b966869fc8b261716e68209e..94381f2033a5b6fda7af0a368d1e100cff329f70 100644 (file)
@@ -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 %T/diamond_bottom.pcm %S/Inputs/diamond_bottom.h
+// RUN: %clang_cc1 -I %T %s -verify
diff --git a/test/Modules/load_failure.c b/test/Modules/load_failure.c
new file mode 100644 (file)
index 0000000..5b5df38
--- /dev/null
@@ -0,0 +1,17 @@
+#ifdef NONEXISTENT
+__import__ load_nonexistent;
+#endif
+
+#ifdef FAILURE
+__import__ load_failure;
+#endif
+
+// RUN: %clang_cc1 -x c++ -emit-module -o %T/load_failure.pcm %S/Inputs/load_failure.h
+// RUN: %clang_cc1 -I %T %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
+// CHECK-NONEXISTENT: load_failure.c:2:12: fatal error: module 'load_nonexistent' not found
+
+// RUN: %clang_cc1 -I %T %s -DFAILURE 2>&1 | FileCheck -check-prefix=CHECK-FAILURE %s
+// FIXME: Clean up diagnostic text below and give it a location
+// CHECK-FAILURE: error: C99 support was disabled in PCH file but is currently enabled
+
+
index e9f52b7c669511edf5e477baef2058630000c301..cae66211caf714a298b4d9eec47afdc5160fd7dc 100644 (file)
@@ -1,3 +1,9 @@
+
+#define import __import__
+import lookup_left_cxx;
+#define IMPORT(X) __import__ X
+IMPORT(lookup_right_cxx);
+
 void test(int i, float f) {
   // unqualified lookup
   f0(&i);
@@ -8,10 +14,10 @@ void test(int i, float f) {
   ::f0(&f);
 }
 
-// RUN: %clang_cc1 -emit-module -x c++ -verify -o %t_lookup_left.h.pch %S/Inputs/lookup_left.hpp
-// RUN: %clang_cc1 -emit-module -x c++ -o %t_lookup_right.h.pch %S/Inputs/lookup_right.hpp
-// RUN: %clang_cc1 -x c++ -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch -verify %s
-// RUN: %clang_cc1 -ast-print -x c++ -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -emit-module -x c++ -verify -o %T/lookup_left_cxx.pcm %S/Inputs/lookup_left.hpp
+// RUN: %clang_cc1 -emit-module -x c++ -o %T/lookup_right_cxx.pcm %S/Inputs/lookup_right.hpp
+// RUN: %clang_cc1 -x c++ -I %T %s -verify
+// RUN: %clang_cc1 -ast-print -x c++ -I %T %s | FileCheck -check-prefix=CHECK-PRINT %s
 
 // CHECK-PRINT: int *f0(int *);
 // CHECK-PRINT: float *f0(float *);
index 85f1dd95d75dec1042dada22d06997e08dce5955..48d0ba9a373ae7b6a458820088cf81ba688a181a 100644 (file)
@@ -1,15 +1,17 @@
 
 // lookup_left.h: expected-note{{using}}
 // lookup_right.h: expected-note{{also found}}
+__import__ lookup_left_objc;
+__import__ lookup_right_objc;
 
 void test(id x) {
   [x method]; // expected-warning{{multiple methods named 'method' found}}
 }
 
-// RUN: %clang_cc1 -emit-module -x objective-c -o %t_lookup_left.h.pch %S/Inputs/lookup_left.h
-// RUN: %clang_cc1 -emit-module -x objective-c -o %t_lookup_right.h.pch %S/Inputs/lookup_right.h
-// RUN: %clang_cc1 -x objective-c -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch -verify %s
-// RUN: %clang_cc1 -ast-print -x objective-c -import-module %t_lookup_left.h.pch -import-module %t_lookup_right.h.pch %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -emit-module -x objective-c -o %T/lookup_left_objc.pcm %S/Inputs/lookup_left.h
+// RUN: %clang_cc1 -emit-module -x objective-c -o %T/lookup_right_objc.pcm %S/Inputs/lookup_right.h
+// RUN: %clang_cc1 -x objective-c -I %T -verify %s
+// RUN: %clang_cc1 -ast-print -x objective-c -I %T %s | FileCheck -check-prefix=CHECK-PRINT %s
 
 // CHECK-PRINT: - (int) method;
 // CHECK-PRINT: - (double) method