]> granicus.if.org Git - clang/commitdiff
Modules hide macro definitions by default, so that silly things like
authorDouglas Gregor <dgregor@apple.com>
Thu, 1 Sep 2011 17:04:32 +0000 (17:04 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 1 Sep 2011 17:04:32 +0000 (17:04 +0000)
include guards don't show up as macro definitions in every translation
unit that imports a module. Macro definitions can, however, be
exported with the intentionally-ugly #__export_macro__
directive. Implement this feature by not even bothering to serialize
non-exported macros to a module, because clients of that module need
not (should not) know that these macros even exist.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138943 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/clang/Basic/DiagnosticLexKinds.td
include/clang/Basic/TokenKinds.def
include/clang/Lex/MacroInfo.h
include/clang/Lex/Preprocessor.h
include/clang/Serialization/ASTWriter.h
lib/Basic/IdentifierTable.cpp
lib/Frontend/ASTUnit.cpp
lib/Frontend/FrontendActions.cpp
lib/Lex/MacroInfo.cpp
lib/Lex/PPDirectives.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ChainedIncludesSource.cpp
lib/Serialization/GeneratePCH.cpp
test/Modules/macros.c [new file with mode: 0644]

index 275e8a1e2897929b6debf4e7fbf0ffd2fc662831..481adc43a424fd57bf7045cf85b200e1778050ff 100644 (file)
@@ -324,4 +324,6 @@ def err_pp_linemarker_invalid_pop : Error<
 def ext_pp_line_too_big : Extension<
   "C requires #line number to be less than %0, allowed as extension">;
 
+def err_pp_export_non_macro : Error<"no macro named %0 to export">;
+
 }
index b5752fe688ac2195fa352df0f48f35715d8acde6..5d68a22ffcb9089642ef5c4a571763be4ed0719d 100644 (file)
@@ -89,6 +89,9 @@ PPKEYWORD(sccs)
 PPKEYWORD(assert)
 PPKEYWORD(unassert)
 
+// Clang extensions
+PPKEYWORD(__export_macro__)
+
 //===----------------------------------------------------------------------===//
 // Language keywords.
 //===----------------------------------------------------------------------===//
index 822a3764b9687d96d1bdef7894c50312cdfc8810..b381e0f25f41add6528736a5a08eea50d3ddb610 100644 (file)
@@ -39,6 +39,11 @@ class MacroInfo {
   IdentifierInfo **ArgumentList;
   unsigned NumArguments;
 
+  /// \brief The location at which this macro was exported from its module.
+  ///
+  /// If invalid, this macro has not been explicitly exported.
+  SourceLocation ExportLocation;
+  
   /// ReplacementTokens - This is the list of tokens that the macro is defined
   /// to.
   SmallVector<Token, 8> ReplacementTokens;
@@ -68,6 +73,9 @@ class MacroInfo {
   /// IsFromAST - True if this macro was loaded from an AST file.
   bool IsFromAST : 1;
 
+  /// \brief Whether this macro changed after it was loaded from an AST file.
+  bool ChangedAfterLoad : 1;
+  
 private:
   //===--------------------------------------------------------------------===//
   // State that changes as the macro is used.
@@ -209,6 +217,14 @@ public:
   /// setIsFromAST - Set whether this macro was loaded from an AST file.
   void setIsFromAST(bool FromAST = true) { IsFromAST = FromAST; }
 
+  /// \brief Determine whether this macro has changed since it was loaded from
+  /// an AST file.
+  bool hasChangedAfterLoad() const { return ChangedAfterLoad; }
+  
+  /// \brief Note whether this macro has changed after it was loaded from an
+  /// AST file.
+  void setChangedAfterLoad(bool CAL = true) { ChangedAfterLoad = CAL; }
+  
   /// isUsed - Return false if this macro is defined in the main file and has
   /// not yet been used.
   bool isUsed() const { return IsUsed; }
@@ -262,6 +278,19 @@ public:
     IsDisabled = true;
   }
 
+  /// \brief Set the export location for this macro.
+  void setExportLocation(SourceLocation ExportLoc) {
+    ExportLocation = ExportLoc;
+  }
+
+  /// \brief Determine whether this macro was explicitly exported from its
+  /// module.
+  bool isExported() const { return ExportLocation.isValid(); }
+  
+  /// \brief Determine the location where this macro was explicitly exported
+  /// from its module.
+  SourceLocation getExportLocation() { return ExportLocation; }
+  
 private:
   unsigned getDefinitionLengthSlow(SourceManager &SM) const;
 };
index f2f3f73b9ba5a1e9fbdb9c94379279d3a86677b3..2871c8f080a30e19bc11e4202ce1b5f6c57a78eb 100644 (file)
@@ -1117,7 +1117,8 @@ private:
   void HandleDigitDirective(Token &Tok);
   void HandleUserDiagnosticDirective(Token &Tok, bool isWarning);
   void HandleIdentSCCSDirective(Token &Tok);
-
+  void HandleMacroExportDirective(Token &Tok);
+  
   // File inclusion.
   void HandleIncludeDirective(SourceLocation HashLoc,
                               Token &Tok,
index cb71415d34f823bb07cbd3a9c4e74a1211e42e87..d872ce260bdbc62dc0e802f19d92db9645e60f60 100644 (file)
@@ -348,7 +348,7 @@ private:
   void WriteSourceManagerBlock(SourceManager &SourceMgr,
                                const Preprocessor &PP,
                                StringRef isysroot);
-  void WritePreprocessor(const Preprocessor &PP);
+  void WritePreprocessor(const Preprocessor &PP, bool IsModule);
   void WriteHeaderSearch(HeaderSearch &HS, StringRef isysroot);
   void WritePreprocessorDetail(PreprocessingRecord &PPRec);
   void WritePragmaDiagnosticMappings(const Diagnostic &Diag);
@@ -359,7 +359,7 @@ private:
   void WriteTypeDeclOffsets();
   void WriteSelectors(Sema &SemaRef);
   void WriteReferencedSelectorsPool(Sema &SemaRef);
-  void WriteIdentifierTable(Preprocessor &PP);
+  void WriteIdentifierTable(Preprocessor &PP, bool IsModule);
   void WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record);
   void WriteDeclUpdatesBlocks();
   void WriteDeclReplacementsBlock();
@@ -386,7 +386,8 @@ private:
   void WriteDecl(ASTContext &Context, Decl *D);
 
   void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
-                    StringRef isysroot, const std::string &OutputFile);
+                    StringRef isysroot, const std::string &OutputFile,
+                    bool IsModule);
   
 public:
   /// \brief Create a new precompiled header writer that outputs to
@@ -407,11 +408,14 @@ public:
   /// \param StatCalls the object that cached all of the stat() calls made while
   /// searching for source files and headers.
   ///
-  /// \param isysroot if non-empty, write a relocatable PCH file whose headers
+  /// \param IsModule Whether we're writing a module (otherwise, we're writing a
+  /// precompiled header).
+  ///
+  /// \param isysroot if non-empty, write a relocatable file whose headers
   /// are relative to the given system root.
   void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
                 const std::string &OutputFile,
-                StringRef isysroot);
+                bool IsModule, StringRef isysroot);
 
   /// \brief Emit a source location.
   void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record);
@@ -643,6 +647,7 @@ public:
 class PCHGenerator : public SemaConsumer {
   const Preprocessor &PP;
   std::string OutputFile;
+  bool IsModule;
   std::string isysroot;
   raw_ostream *Out;
   Sema *SemaPtr;
@@ -657,6 +662,7 @@ protected:
 
 public:
   PCHGenerator(const Preprocessor &PP, StringRef OutputFile, 
+               bool IsModule,
                StringRef isysroot, raw_ostream *Out);
   ~PCHGenerator();
   virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
index 792b0c9c6171f5505381ed9268cf559523bde7e4..0103318405c6172d164deebe10b772e694dcec53 100644 (file)
@@ -217,6 +217,7 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
   CASE(12, 'i', 'c', include_next);
 
   CASE(16, '_', 'i', __include_macros);
+  CASE(16, '_', 'e', __export_macro__);
 #undef CASE
 #undef HASH
   }
index cc96d486b10baf5c7ee0040057b2f9425b2a383a..eee5b1a7ccabe30421a49af08c51e048d2531d87 100644 (file)
@@ -771,7 +771,7 @@ class PrecompilePreambleConsumer : public PCHGenerator,
 public:
   PrecompilePreambleConsumer(ASTUnit &Unit, const Preprocessor &PP, 
                              StringRef isysroot, raw_ostream *Out)
-    : PCHGenerator(PP, "", isysroot, Out), Unit(Unit),
+    : PCHGenerator(PP, "", /*IsModule=*/false, isysroot, Out), Unit(Unit),
       Hash(Unit.getCurrentTopLevelHashValue()) {
     Hash = 0;
   }
@@ -2324,7 +2324,8 @@ bool ASTUnit::serialize(raw_ostream &OS) {
   std::vector<unsigned char> Buffer;
   llvm::BitstreamWriter Stream(Buffer);
   ASTWriter Writer(Stream);
-  Writer.WriteAST(getSema(), 0, std::string(), "");
+  // FIXME: Handle modules
+  Writer.WriteAST(getSema(), 0, std::string(), /*IsModule=*/false, "");
   
   // Write the generated bitstream to "Out".
   if (!Buffer.empty())
index e05d5767eaa398196405b7ba30cc8daf8eeb92dc..c80802e3532b12f489132281d94d63f06422c4c4 100644 (file)
@@ -83,7 +83,8 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
 
   if (!CI.getFrontendOpts().RelocatablePCH)
     Sysroot.clear();
-  return new PCHGenerator(CI.getPreprocessor(), OutputFile, Sysroot, OS);
+  return new PCHGenerator(CI.getPreprocessor(), OutputFile, MakeModule, 
+                          Sysroot, OS);
 }
 
 bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
index 9e682ce30654e859266ce4397b9167dced5e2aff..5a7af5639830916b45fd17f0a43821df7f5882a0 100644 (file)
@@ -21,6 +21,7 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) {
   IsGNUVarargs = false;
   IsBuiltinMacro = false;
   IsFromAST = false;
+  ChangedAfterLoad = false;
   IsDisabled = false;
   IsUsed = false;
   IsAllowRedefinitionsWithoutWarning = false;
@@ -40,6 +41,7 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) {
   IsGNUVarargs = MI.IsGNUVarargs;
   IsBuiltinMacro = MI.IsBuiltinMacro;
   IsFromAST = MI.IsFromAST;
+  ChangedAfterLoad = MI.ChangedAfterLoad;
   IsDisabled = MI.IsDisabled;
   IsUsed = MI.IsUsed;
   IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning;
index 99383e4791ba17bb5ce4fdf85dd9874337061411..c8fcc3e37d140e28b3445ff155c687f37ca54980 100644 (file)
@@ -652,6 +652,9 @@ TryAgain:
     case tok::pp_unassert:
       //isExtension = true;  // FIXME: implement #unassert
       break;
+        
+    case tok::pp___export_macro__:
+      return HandleMacroExportDirective(Result);
     }
     break;
   }
@@ -1000,6 +1003,37 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) {
   }
 }
 
+/// \brief Handle a #__export_macro__ directive.
+void Preprocessor::HandleMacroExportDirective(Token &Tok) {
+  Token MacroNameTok;
+  ReadMacroName(MacroNameTok, 2);
+  
+  // Error reading macro name?  If so, diagnostic already issued.
+  if (MacroNameTok.is(tok::eod))
+    return;
+
+  // Check to see if this is the last token on the #__export_macro__ line.
+  CheckEndOfDirective("__export_macro__");
+
+  // Okay, we finally have a valid identifier to undef.
+  MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+  
+  // If the macro is not defined, this is an error.
+  if (MI == 0) {
+    Diag(MacroNameTok, diag::err_pp_export_non_macro)
+      << MacroNameTok.getIdentifierInfo();
+    return;
+  }
+  
+  // Note that this macro has now been exported.
+  MI->setExportLocation(MacroNameTok.getLocation());
+  
+  // If this macro definition came from a PCH file, mark it
+  // as having changed since serialization.
+  if (MI->isFromAST())
+    MI->setChangedAfterLoad();
+}
+
 //===----------------------------------------------------------------------===//
 // Preprocessor Include Directive Handling.
 //===----------------------------------------------------------------------===//
index bc022f5721b59c7ab872679afd4c4c292e3f6ea8..10b01d8c9f9073eea576cf15a052afd2592ec856 100644 (file)
@@ -1352,15 +1352,16 @@ void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) {
       MI->setIsFromAST();
 
       unsigned NextIndex = 3;
+      MI->setExportLocation(ReadSourceLocation(F, Record, NextIndex));
+      
       if (RecType == PP_MACRO_FUNCTION_LIKE) {
         // Decode function-like macro info.
-        bool isC99VarArgs = Record[3];
-        bool isGNUVarArgs = Record[4];
+        bool isC99VarArgs = Record[NextIndex++];
+        bool isGNUVarArgs = Record[NextIndex++];
         MacroArgs.clear();
-        unsigned NumArgs = Record[5];
-        NextIndex = 6 + NumArgs;
+        unsigned NumArgs = Record[NextIndex++];
         for (unsigned i = 0; i != NumArgs; ++i)
-          MacroArgs.push_back(getLocalIdentifier(F, Record[6+i]));
+          MacroArgs.push_back(getLocalIdentifier(F, Record[NextIndex++]));
 
         // Install function-like macro info.
         MI->setIsFunctionLike();
index a57f3a1388f0018974b9013d9cb1eea621c81de5..f2ff332de13d6c551984ff0dba434a2174f38797 100644 (file)
@@ -1667,7 +1667,7 @@ static int compareMacroDefinitions(const void *XPtr, const void *YPtr) {
 /// \brief Writes the block containing the serialized form of the
 /// preprocessor.
 ///
-void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
+void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
   RecordData Record;
 
   // If the preprocessor __COUNTER__ value has been bumped, remember it.
@@ -1697,8 +1697,10 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
   for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), 
                                     E = PP.macro_end(Chain == 0);
        I != E; ++I) {
-    MacroDefinitionsSeen.insert(I->first);
-    MacrosToEmit.push_back(std::make_pair(I->first, I->second));
+    if (!IsModule || I->second->isExported()) {
+      MacroDefinitionsSeen.insert(I->first);
+      MacrosToEmit.push_back(std::make_pair(I->first, I->second));
+    }
   }
   
   // Sort the set of macro definitions that need to be serialized by the
@@ -1730,14 +1732,15 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
     // chained PCH, by storing the offset into the original PCH rather than
     // writing the macro definition a second time.
     if (MI->isBuiltinMacro() ||
-        (Chain && Name->isFromAST() && MI->isFromAST()))
+        (Chain && Name->isFromAST() && MI->isFromAST() &&
+        !MI->hasChangedAfterLoad()))
       continue;
 
     AddIdentifierRef(Name, Record);
     MacroOffsets[Name] = Stream.GetCurrentBitNo();
     Record.push_back(MI->getDefinitionLoc().getRawEncoding());
     Record.push_back(MI->isUsed());
-
+    AddSourceLocation(MI->getExportLocation(), Record);
     unsigned Code;
     if (MI->isObjectLike()) {
       Code = PP_MACRO_OBJECT_LIKE;
@@ -2293,38 +2296,52 @@ namespace {
 class ASTIdentifierTableTrait {
   ASTWriter &Writer;
   Preprocessor &PP;
-
+  bool IsModule;
+  
   /// \brief Determines whether this is an "interesting" identifier
   /// that needs a full IdentifierInfo structure written into the hash
   /// table.
-  static bool isInterestingIdentifier(const IdentifierInfo *II) {
-    return II->isPoisoned() ||
-      II->isExtensionToken() ||
-      II->hasMacroDefinition() ||
-      II->getObjCOrBuiltinID() ||
-      II->getFETokenInfo<void>();
+  bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) {
+    Macro = 0;
+    
+    if (II->isPoisoned() ||
+        II->isExtensionToken() ||
+        II->getObjCOrBuiltinID() ||
+        II->getFETokenInfo<void>())
+      return true;
+
+    if (!II->hasMacroDefinition())
+      return false;
+    
+    if (!IsModule)
+      return true;
+    
+    if ((Macro = PP.getMacroInfo(II)))
+      return Macro->isExported();
+    
+    return false;
   }
 
 public:
-  typedef const IdentifierInfo* key_type;
+  typedef IdentifierInfo* key_type;
   typedef key_type  key_type_ref;
 
   typedef IdentID data_type;
   typedef data_type data_type_ref;
 
-  ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP)
-    : Writer(Writer), PP(PP) { }
+  ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP, bool IsModule)
+    : Writer(Writer), PP(PP), IsModule(IsModule) { }
 
   static unsigned ComputeHash(const IdentifierInfo* II) {
     return llvm::HashString(II->getName());
   }
 
   std::pair<unsigned,unsigned>
-    EmitKeyDataLength(raw_ostream& Out, const IdentifierInfo* II,
-                      IdentID ID) {
+    EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
     unsigned KeyLen = II->getLength() + 1;
     unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
-    if (isInterestingIdentifier(II)) {
+    MacroInfo *Macro;
+    if (isInterestingIdentifier(II, Macro)) {
       DataLen += 2; // 2 bytes for builtin ID, flags
       if (II->hasMacroDefinition() &&
           !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro())
@@ -2350,18 +2367,19 @@ public:
     Out.write(II->getNameStart(), KeyLen);
   }
 
-  void EmitData(raw_ostream& Out, const IdentifierInfo* II,
+  void EmitData(raw_ostream& Out, IdentifierInfo* II,
                 IdentID ID, unsigned) {
-    if (!isInterestingIdentifier(II)) {
+    MacroInfo *Macro;
+    if (!isInterestingIdentifier(II, Macro)) {
       clang::io::Emit32(Out, ID << 1);
       return;
     }
 
     clang::io::Emit32(Out, (ID << 1) | 0x01);
     uint32_t Bits = 0;
-    bool hasMacroDefinition =
-      II->hasMacroDefinition() &&
-      !PP.getMacroInfo(const_cast<IdentifierInfo *>(II))->isBuiltinMacro();
+    bool hasMacroDefinition 
+      = II->hasMacroDefinition() && 
+        (Macro || (Macro = PP.getMacroInfo(II))) && !Macro->isBuiltinMacro();
     Bits = (uint32_t)II->getObjCOrBuiltinID();
     Bits = (Bits << 1) | unsigned(hasMacroDefinition);
     Bits = (Bits << 1) | unsigned(II->isExtensionToken());
@@ -2395,14 +2413,14 @@ public:
 /// The identifier table consists of a blob containing string data
 /// (the actual identifiers themselves) and a separate "offsets" index
 /// that maps identifier IDs to locations within the blob.
-void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
+void ASTWriter::WriteIdentifierTable(Preprocessor &PP, bool IsModule) {
   using namespace llvm;
 
   // Create and write out the blob that contains the identifier
   // strings.
   {
     OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
-    ASTIdentifierTableTrait Trait(*this, PP);
+    ASTIdentifierTableTrait Trait(*this, PP, IsModule);
 
     // Look for any identifiers that were named while processing the
     // headers, but are otherwise not needed. We add these to the hash
@@ -2422,14 +2440,15 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) {
          ID != IDEnd; ++ID) {
       assert(ID->first && "NULL identifier in identifier table");
       if (!Chain || !ID->first->isFromAST())
-        Generator.insert(ID->first, ID->second, Trait);
+        Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second, 
+                         Trait);
     }
 
     // Create the on-disk hash table in a buffer.
     llvm::SmallString<4096> IdentifierTable;
     uint32_t BucketOffset;
     {
-      ASTIdentifierTableTrait Trait(*this, PP);
+      ASTIdentifierTableTrait Trait(*this, PP, IsModule);
       llvm::raw_svector_ostream Out(IdentifierTable);
       // Make sure that no bucket is at offset 0
       clang::io::Emit32(Out, 0);
@@ -2818,7 +2837,7 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream)
 
 void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
                          const std::string &OutputFile,
-                         StringRef isysroot) {
+                         bool IsModule, StringRef isysroot) {
   // Emit the file header.
   Stream.Emit((unsigned)'C', 8);
   Stream.Emit((unsigned)'P', 8);
@@ -2828,7 +2847,7 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   WriteBlockInfoBlock();
 
   Context = &SemaRef.Context;
-  WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile);
+  WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, IsModule);
   Context = 0;
 }
 
@@ -2843,7 +2862,7 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec,
 
 void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
                              StringRef isysroot,
-                             const std::string &OutputFile) {
+                             const std::string &OutputFile, bool IsModule) {
   using namespace llvm;
 
   ASTContext &Context = SemaRef.Context;
@@ -3095,11 +3114,11 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   }
   Stream.ExitBlock();
 
-  WritePreprocessor(PP);
+  WritePreprocessor(PP, IsModule);
   WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
   WriteSelectors(SemaRef);
   WriteReferencedSelectorsPool(SemaRef);
-  WriteIdentifierTable(PP);
+  WriteIdentifierTable(PP, IsModule);
   WriteFPPragmaOptions(SemaRef.getFPOptions());
   WriteOpenCLExtensions(SemaRef);
 
index 56dc07f4cb401b1909c0a974bd066b4b4a658737..e354054fb1f8a5d904454d27c5090529eb01fc22 100644 (file)
@@ -106,7 +106,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
     llvm::raw_svector_ostream OS(serialAST);
     llvm::OwningPtr<ASTConsumer> consumer;
     consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-",
-                                    /*isysroot=*/"", &OS));
+                                    /*IsModule=*/false, /*isysroot=*/"", &OS));
     Clang->getASTContext().setASTMutationListener(
                                             consumer->GetASTMutationListener());
     Clang->setASTConsumer(consumer.take());
index 358954ed1993a67cadb2b76f5da3dec5660b561c..25fac8b7a8e25226172449f83429977d75ed7039 100644 (file)
@@ -28,9 +28,11 @@ using namespace clang;
 
 PCHGenerator::PCHGenerator(const Preprocessor &PP,
                            StringRef OutputFile,
+                           bool IsModule,
                            StringRef isysroot,
                            raw_ostream *OS)
-  : PP(PP), OutputFile(OutputFile), isysroot(isysroot.str()), Out(OS), 
+  : PP(PP), OutputFile(OutputFile), IsModule(IsModule), 
+    isysroot(isysroot.str()), Out(OS), 
     SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) {
   // Install a stat() listener to keep track of all of the stat()
   // calls.
@@ -50,7 +52,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
   
   // Emit the PCH file
   assert(SemaPtr && "No Sema?");
-  Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, isysroot);
+  Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, IsModule, isysroot);
 
   // Write the generated bitstream to "Out".
   Out->write((char *)&Buffer.front(), Buffer.size());
diff --git a/test/Modules/macros.c b/test/Modules/macros.c
new file mode 100644 (file)
index 0000000..691e8ec
--- /dev/null
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -emit-module -o %t/macros.pcm -DMODULE %s
+// RUN: %clang_cc1 -verify -I %t %s
+
+#if defined(MODULE)
+#define INTEGER(X) int
+#define FLOAT float
+#define DOUBLE double
+
+#__export_macro__ INTEGER
+#__export_macro__ DOUBLE
+
+#else
+
+__import_module__ macros;
+
+#ifndef INTEGER
+#  error INTEGER macro should be visible
+#endif
+
+#ifdef FLOAT
+#  error FLOAT macro should not be visible
+#endif
+
+#ifdef MODULE
+#  error MODULE macro should not be visible
+#endif
+
+double d;
+DOUBLE *dp = &d;
+
+#__export_macro__ WIBBLE // expected-error{{no macro named 'WIBBLE' to export}}
+
+#endif