From: Douglas Gregor Date: Mon, 17 Oct 2011 15:32:29 +0000 (+0000) Subject: For modules, all macros that aren't include guards are implicitly X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa93a875605536d72a10359a0098396192b7d4ec;p=clang For modules, all macros that aren't include guards are implicitly public. Add a __private_macro__ directive to hide a macro, similar to the __module_private__ declaration specifier. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142188 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 9b3a178cac..664d390ac7 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -355,7 +355,7 @@ def warn_cxx98_compat_pp_line_too_big : Warning< "#line number greater than 32767 is incompatible with C++98">, InGroup, DefaultIgnore; -def err_pp_export_non_macro : Error<"no macro named %0 to export">; +def err_pp_visibility_non_macro : Error<"no macro named %0">; def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">; def err_pp_double_begin_of_arc_cf_code_audited : Error< diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 35a881c660..cd0cd06a61 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -91,6 +91,7 @@ PPKEYWORD(unassert) // Clang extensions PPKEYWORD(__export_macro__) +PPKEYWORD(__private_macro__) //===----------------------------------------------------------------------===// // Language keywords. diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index b381e0f25f..8775d39fe8 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -39,10 +39,11 @@ class MacroInfo { IdentifierInfo **ArgumentList; unsigned NumArguments; - /// \brief The location at which this macro was exported from its module. + /// \brief The location at which this macro was either explicitly exported + /// from its module or marked as private. /// - /// If invalid, this macro has not been explicitly exported. - SourceLocation ExportLocation; + /// If invalid, this macro has not been explicitly given any visibility. + SourceLocation VisibilityLocation; /// ReplacementTokens - This is the list of tokens that the macro is defined /// to. @@ -97,6 +98,9 @@ private: /// \brief Must warn if the macro is unused at the end of translation unit. bool IsWarnIfUnused : 1; + /// \brief Whether the macro has public (when described in a module). + bool IsPublic : 1; + ~MacroInfo() { assert(ArgumentList == 0 && "Didn't call destroy before dtor!"); } @@ -279,17 +283,18 @@ public: } /// \brief Set the export location for this macro. - void setExportLocation(SourceLocation ExportLoc) { - ExportLocation = ExportLoc; + void setVisibility(bool Public, SourceLocation Loc) { + VisibilityLocation = Loc; + IsPublic = Public; } - /// \brief Determine whether this macro was explicitly exported from its + /// \brief Determine whether this macro is part of the public API of its /// module. - bool isExported() const { return ExportLocation.isValid(); } + bool isPublic() const { return IsPublic; } - /// \brief Determine the location where this macro was explicitly exported - /// from its module. - SourceLocation getExportLocation() { return ExportLocation; } + /// \brief Determine the location where this macro was explicitly made + /// public or private within its module. + SourceLocation getVisibilityLocation() { return VisibilityLocation; } private: unsigned getDefinitionLengthSlow(SourceManager &SM) const; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 8b7743316f..50d6a2adc9 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -1183,6 +1183,7 @@ private: void HandleUserDiagnosticDirective(Token &Tok, bool isWarning); void HandleIdentSCCSDirective(Token &Tok); void HandleMacroExportDirective(Token &Tok); + void HandleMacroPrivateDirective(Token &Tok); // File inclusion. void HandleIncludeDirective(SourceLocation HashLoc, diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 38f09a08af..78f8a7cbdb 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -222,6 +222,8 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { CASE(16, '_', 'i', __include_macros); CASE(16, '_', 'e', __export_macro__); + + CASE(17, '_', 'p', __private_macro__); #undef CASE #undef HASH } diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp index 5a7af56398..3d0c9a1c2b 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -27,7 +27,8 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) { IsAllowRedefinitionsWithoutWarning = false; IsWarnIfUnused = false; IsDefinitionLengthCached = false; - + IsPublic = true; + ArgumentList = 0; NumArguments = 0; } @@ -48,6 +49,8 @@ MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) { IsWarnIfUnused = MI.IsWarnIfUnused; IsDefinitionLengthCached = MI.IsDefinitionLengthCached; DefinitionLength = MI.DefinitionLength; + IsPublic = MI.IsPublic; + ArgumentList = 0; NumArguments = 0; setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator); diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index de50c750e4..9446d51f9d 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -666,6 +666,8 @@ TryAgain: case tok::pp___export_macro__: return HandleMacroExportDirective(Result); + case tok::pp___private_macro__: + return HandleMacroPrivateDirective(Result); } break; } @@ -1035,13 +1037,44 @@ void Preprocessor::HandleMacroExportDirective(Token &Tok) { // If the macro is not defined, this is an error. if (MI == 0) { - Diag(MacroNameTok, diag::err_pp_export_non_macro) + Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << MacroNameTok.getIdentifierInfo(); return; } // Note that this macro has now been exported. - MI->setExportLocation(MacroNameTok.getLocation()); + MI->setVisibility(/*IsPublic=*/true, MacroNameTok.getLocation()); + + // If this macro definition came from a PCH file, mark it + // as having changed since serialization. + if (MI->isFromAST()) + MI->setChangedAfterLoad(); +} + +/// \brief Handle a #__private_macro__ directive. +void Preprocessor::HandleMacroPrivateDirective(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 #__private_macro__ line. + CheckEndOfDirective("__private_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_visibility_non_macro) + << MacroNameTok.getIdentifierInfo(); + return; + } + + // Note that this macro has now been marked private. + MI->setVisibility(/*IsPublic=*/false, MacroNameTok.getLocation()); // If this macro definition came from a PCH file, mark it // as having changed since serialization. diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 25a98ae47b..da6c8aa589 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -16,6 +16,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/MemoryBuffer.h" using namespace clang; @@ -211,8 +212,28 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { CurPPLexer->MIOpt.GetControllingMacroAtEndOfFile()) { // Okay, this has a controlling macro, remember in HeaderFileInfo. if (const FileEntry *FE = - SourceMgr.getFileEntryForID(CurPPLexer->getFileID())) + SourceMgr.getFileEntryForID(CurPPLexer->getFileID())) { HeaderInfo.SetFileControllingMacro(FE, ControllingMacro); + + // Controlling macros are implicitly private. + if (MacroInfo *MI = getMacroInfo( + const_cast(ControllingMacro))) { + if (MI->getVisibilityLocation().isInvalid()) { + // FIXME: HACK! Mark controlling macros from system headers as + // exported, along with our own Clang headers. This is a gross + // hack to deal with the fact that system headers are included in + // many places within module headers, but are not themselves + // modularized. + if ((StringRef(FE->getName()).find("lib/clang") + == StringRef::npos) && + (StringRef(FE->getName()).find("usr/include") + == StringRef::npos) && + (StringRef(FE->getName()).find("usr/local/include") + == StringRef::npos)) + MI->setVisibility(false, SourceLocation()); + } + } + } } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 533b21cb43..4a9d8a5efb 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -468,34 +468,6 @@ void Sema::ActOnEndOfTranslationUnit() { } if (TUKind == TU_Module) { - // Mark any macros from system headers (in /usr/include) as exported, along - // with our own Clang headers. - // FIXME: This is a gross hack to deal with the fact that system headers - // are #include'd in many places within module headers, but are not - // themselves modularized. This doesn't actually work, but it lets us - // focus on other issues for the moment. - for (Preprocessor::macro_iterator M = PP.macro_begin(false), - MEnd = PP.macro_end(false); - M != MEnd; ++M) { - if (M->second && - !M->second->isExported() && - !M->second->isBuiltinMacro()) { - SourceLocation Loc = M->second->getDefinitionLoc(); - if (SourceMgr.isInSystemHeader(Loc)) { - const FileEntry *File - = SourceMgr.getFileEntryForID(SourceMgr.getFileID(Loc)); - if (File && - ((StringRef(File->getName()).find("lib/clang") - != StringRef::npos) || - (StringRef(File->getName()).find("usr/include") - != StringRef::npos) || - (StringRef(File->getName()).find("usr/local/include") - != StringRef::npos))) - M->second->setExportLocation(Loc); - } - } - } - // Modules don't need any of the checking below. TUScope = 0; return; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index fe1cc30158..dc7829f3e9 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1283,8 +1283,9 @@ void ASTReader::ReadMacroRecord(Module &F, uint64_t Offset) { MI->setIsUsed(isUsed); MI->setIsFromAST(); - unsigned NextIndex = 3; - MI->setExportLocation(ReadSourceLocation(F, Record, NextIndex)); + bool IsPublic = Record[3]; + unsigned NextIndex = 4; + MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex)); if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index b31262d375..ba9a82bbb7 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1629,7 +1629,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), E = PP.macro_end(Chain == 0); I != E; ++I) { - if (!IsModule || I->second->isExported()) { + if (!IsModule || I->second->isPublic()) { MacroDefinitionsSeen.insert(I->first); MacrosToEmit.push_back(std::make_pair(I->first, I->second)); } @@ -1672,7 +1672,8 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { MacroOffsets[Name] = Stream.GetCurrentBitNo(); Record.push_back(MI->getDefinitionLoc().getRawEncoding()); Record.push_back(MI->isUsed()); - AddSourceLocation(MI->getExportLocation(), Record); + Record.push_back(MI->isPublic()); + AddSourceLocation(MI->getVisibilityLocation(), Record); unsigned Code; if (MI->isObjectLike()) { Code = PP_MACRO_OBJECT_LIKE; @@ -2210,7 +2211,7 @@ class ASTIdentifierTableTrait { return false; if (Macro || (Macro = PP.getMacroInfo(II))) - return !Macro->isBuiltinMacro() && (!IsModule || Macro->isExported()); + return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic()); return false; } diff --git a/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h b/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h index fa40697745..411e97868c 100644 --- a/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h +++ b/test/Modules/Inputs/DependsOnModule.framework/Headers/DependsOnModule.h @@ -1,3 +1,5 @@ #include #define DEPENDS_ON_MODULE 1 +#__private_macro__ DEPENDS_ON_MODULE + diff --git a/test/Modules/Inputs/Module.framework/Headers/Module.h b/test/Modules/Inputs/Module.framework/Headers/Module.h index 7c7ef6ea10..9bf6a27edf 100644 --- a/test/Modules/Inputs/Module.framework/Headers/Module.h +++ b/test/Modules/Inputs/Module.framework/Headers/Module.h @@ -1,3 +1,5 @@ +#ifndef MODULE_H +#define MODULE_H const char *getModuleVersion(void); #ifdef FOO @@ -10,3 +12,6 @@ const char *getModuleVersion(void); @end #define MODULE_H_MACRO 1 +#__private_macro__ MODULE_H_MACRO + +#endif // MODULE_H diff --git a/test/Modules/macros.c b/test/Modules/macros.c index 899c19bb29..e371237bb0 100644 --- a/test/Modules/macros.c +++ b/test/Modules/macros.c @@ -8,7 +8,8 @@ #define DOUBLE double #__export_macro__ INTEGER -#__export_macro__ DOUBLE +#__private_macro__ FLOAT +#__private_macro__ MODULE int (INTEGER); diff --git a/test/Modules/on-demand-build.m b/test/Modules/on-demand-build.m index 649caa8a7d..2c6a759b43 100644 --- a/test/Modules/on-demand-build.m +++ b/test/Modules/on-demand-build.m @@ -6,6 +6,8 @@ __import_module__ Module; @interface OtherClass @end + + // in module: expected-note{{class method 'alloc' is assumed to return an instance of its receiver type ('Module *')}} void test_getModuleVersion() { const char *version = getModuleVersion(); @@ -14,4 +16,7 @@ void test_getModuleVersion() { OtherClass *other = [Module alloc]; // expected-error{{init}} } +#ifdef MODULE_H +# error MODULE_H should not be hidden +#endif