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:
parent
71129d5e9e
commit
ebf0049901
|
@ -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<
|
||||
|
|
|
@ -91,6 +91,7 @@ PPKEYWORD(unassert)
|
|||
|
||||
// Clang extensions
|
||||
PPKEYWORD(__export_macro__)
|
||||
PPKEYWORD(__private_macro__)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Language keywords.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <Module/Module.h>
|
||||
|
||||
#define DEPENDS_ON_MODULE 1
|
||||
#__private_macro__ DEPENDS_ON_MODULE
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
#define DOUBLE double
|
||||
|
||||
#__export_macro__ INTEGER
|
||||
#__export_macro__ DOUBLE
|
||||
#__private_macro__ FLOAT
|
||||
#__private_macro__ MODULE
|
||||
|
||||
int (INTEGER);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue