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.

llvm-svn: 142188
This commit is contained in:
Douglas Gregor 2011-10-17 15:32:29 +00:00
parent 71129d5e9e
commit ebf0049901
15 changed files with 102 additions and 49 deletions

View File

@ -355,7 +355,7 @@ def warn_cxx98_compat_pp_line_too_big : Warning<
"#line number greater than 32767 is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, 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<

View File

@ -91,6 +91,7 @@ PPKEYWORD(unassert)
// Clang extensions
PPKEYWORD(__export_macro__)
PPKEYWORD(__private_macro__)
//===----------------------------------------------------------------------===//
// Language keywords.

View File

@ -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;

View File

@ -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,

View File

@ -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
}

View File

@ -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);

View File

@ -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.

View File

@ -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<IdentifierInfo *>(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());
}
}
}
}
}

View File

@ -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;

View File

@ -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.

View File

@ -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;
}

View File

@ -1,3 +1,5 @@
#include <Module/Module.h>
#define DEPENDS_ON_MODULE 1
#__private_macro__ DEPENDS_ON_MODULE

View File

@ -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

View File

@ -8,7 +8,8 @@
#define DOUBLE double
#__export_macro__ INTEGER
#__export_macro__ DOUBLE
#__private_macro__ FLOAT
#__private_macro__ MODULE
int (INTEGER);

View File

@ -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