aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-09-01 17:04:32 +0000
committerDouglas Gregor <dgregor@apple.com>2011-09-01 17:04:32 +0000
commit7143aab97c6e849a5a5005b7853b8c7d5af008ed (patch)
tree1d717dfe03b6e8ad673920a17b021fb3faf6912d
parent8efcc0184a6dfe1ea799d3a6b9c1312ef1fac11d (diff)
Modules hide macro definitions by default, so that silly things like
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
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td2
-rw-r--r--include/clang/Basic/TokenKinds.def3
-rw-r--r--include/clang/Lex/MacroInfo.h29
-rw-r--r--include/clang/Lex/Preprocessor.h3
-rw-r--r--include/clang/Serialization/ASTWriter.h16
-rw-r--r--lib/Basic/IdentifierTable.cpp1
-rw-r--r--lib/Frontend/ASTUnit.cpp5
-rw-r--r--lib/Frontend/FrontendActions.cpp3
-rw-r--r--lib/Lex/MacroInfo.cpp2
-rw-r--r--lib/Lex/PPDirectives.cpp34
-rw-r--r--lib/Serialization/ASTReader.cpp11
-rw-r--r--lib/Serialization/ASTWriter.cpp83
-rw-r--r--lib/Serialization/ChainedIncludesSource.cpp2
-rw-r--r--lib/Serialization/GeneratePCH.cpp6
-rw-r--r--test/Modules/macros.c33
15 files changed, 184 insertions, 49 deletions
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 275e8a1e28..481adc43a4 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -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">;
+
}
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index b5752fe688..5d68a22ffc 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -89,6 +89,9 @@ PPKEYWORD(sccs)
PPKEYWORD(assert)
PPKEYWORD(unassert)
+// Clang extensions
+PPKEYWORD(__export_macro__)
+
//===----------------------------------------------------------------------===//
// Language keywords.
//===----------------------------------------------------------------------===//
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index 822a3764b9..b381e0f25f 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -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;
};
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index f2f3f73b9b..2871c8f080 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -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,
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index cb71415d34..d872ce260b 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -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; }
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 792b0c9c61..0103318405 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -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
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index cc96d486b1..eee5b1a7cc 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -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())
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index e05d5767ea..c80802e353 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -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,
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 9e682ce306..5a7af56398 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -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;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 99383e4791..c8fcc3e37d 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -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.
//===----------------------------------------------------------------------===//
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index bc022f5721..10b01d8c9f 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -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();
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index a57f3a1388..f2ff332de1 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -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);
diff --git a/lib/Serialization/ChainedIncludesSource.cpp b/lib/Serialization/ChainedIncludesSource.cpp
index 56dc07f4cb..e354054fb1 100644
--- a/lib/Serialization/ChainedIncludesSource.cpp
+++ b/lib/Serialization/ChainedIncludesSource.cpp
@@ -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());
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 358954ed19..25fac8b7a8 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -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
index 0000000000..691e8ec0ec
--- /dev/null
+++ b/test/Modules/macros.c
@@ -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