summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-09-09 02:06:17 +0000
committerDouglas Gregor <dgregor@apple.com>2011-09-09 02:06:17 +0000
commit8d267c57afb3af418ed5281b7a9bb4555d701a82 (patch)
treed38cfe3af21da70e2686d0bc251f6b0925ca0960
parentf81e5a9e3f3ff80c56e4afb4fe6311a8735f36e8 (diff)
Modules: introduce the __module_private__ declaration specifier, which
indicates that a declaration is only visible within the module it is declared in. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139348 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/Decl.h10
-rw-r--r--include/clang/AST/DeclBase.h12
-rw-r--r--include/clang/Basic/TokenKinds.def1
-rw-r--r--include/clang/Sema/DeclSpec.h8
-rw-r--r--include/clang/Sema/Lookup.h14
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--lib/AST/DeclPrinter.cpp19
-rw-r--r--lib/Parse/ParseDecl.cpp11
-rw-r--r--lib/Parse/ParseDeclCXX.cpp1
-rw-r--r--lib/Parse/ParseTentative.cpp9
-rw-r--r--lib/Sema/DeclSpec.cpp12
-rw-r--r--lib/Sema/SemaDecl.cpp17
-rw-r--r--lib/Sema/SemaDeclCXX.cpp1
-rw-r--r--lib/Sema/SemaTemplate.cpp12
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp15
-rw-r--r--test/Modules/module-private.cpp56
17 files changed, 186 insertions, 16 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 4cb7218369..786cc24760 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -180,6 +180,16 @@ public:
/// \brief Determine whether this declaration has linkage.
bool hasLinkage() const;
+ /// \brief Whether this declaration was marked as being private to the
+ /// module in which it was defined.
+ bool isModulePrivate() const { return ModulePrivate; }
+
+ /// \brief Specify whether this declaration was marked as being private
+ /// to the module in which it was defined.
+ void setModulePrivate(bool MP = true) {
+ ModulePrivate = MP;
+ }
+
/// \brief Determine whether this declaration is a C++ class member.
bool isCXXClassMember() const {
const DeclContext *DC = getDeclContext();
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 55f89734e0..14d811fa67 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -243,7 +243,7 @@ private:
/// evaluated context or not, e.g. functions used in uninstantiated templates
/// are regarded as "referenced" but not "used".
unsigned Referenced : 1;
-
+
protected:
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
@@ -256,6 +256,10 @@ protected:
/// ChangedAfterLoad - if this declaration has changed since being loaded
unsigned ChangedAfterLoad : 1;
+ /// \brief Whether this declaration is private to the module in which it was
+ /// defined.
+ unsigned ModulePrivate : 1;
+
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
unsigned IdentifierNamespace : 12;
@@ -269,7 +273,9 @@ protected:
/// This field is only valid for NamedDecls subclasses.
mutable unsigned CachedLinkage : 2;
-
+ friend class ASTDeclWriter;
+ friend class ASTDeclReader;
+
private:
void CheckAccessDeclContext() const;
@@ -280,6 +286,7 @@ protected:
Loc(L), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
+ ModulePrivate(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
{
@@ -290,6 +297,7 @@ protected:
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
+ ModulePrivate(0),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
{
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 5d68a22ffc..534aebbf77 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -401,6 +401,7 @@ KEYWORD(__array_extent , KEYCXX)
// Apple Extension.
KEYWORD(__private_extern__ , KEYALL)
KEYWORD(__import_module__ , KEYALL)
+KEYWORD(__module_private__ , KEYALL)
// Microsoft Extension.
KEYWORD(__declspec , KEYALL)
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index cdd7dbaa6d..177de65a34 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -345,7 +345,7 @@ private:
SourceRange TypeofParensRange;
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
- SourceLocation FriendLoc, ConstexprLoc;
+ SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
@@ -592,13 +592,17 @@ public:
bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
-
+ bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID);
bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
bool isFriendSpecified() const { return Friend_specified; }
SourceLocation getFriendSpecLoc() const { return FriendLoc; }
+ bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); }
+ SourceLocation getModulePrivateSpecLoc() const { return ModulePrivateLoc; }
+
bool isConstexprSpecified() const { return Constexpr_specified; }
SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 1a11dfaad8..1fa9066cf2 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -268,7 +268,19 @@ public:
/// \brief Tests whether the given declaration is acceptable.
bool isAcceptableDecl(NamedDecl *D) const {
- return D->isInIdentifierNamespace(IDNS);
+ if (!D->isInIdentifierNamespace(IDNS))
+ return false;
+
+ // So long as this declaration is not module-private or was parsed as
+ // part of this translation unit (i.e., in the module), we're allowed to
+ // find it.
+ if (!D->isModulePrivate() || D->getPCHLevel() == 0)
+ return true;
+
+ // FIXME: We should be allowed to refer to a module-private name from
+ // within the same module, e.g., during template instantiation.
+ // This requires us know which module a particular declaration came from.
+ return false;
}
/// \brief Returns the identifier namespace mask for this lookup.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 935fe9947c..fc2a7f55c4 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1131,6 +1131,7 @@ public:
SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
+ bool IsModulePrivate,
MultiTemplateParamsArg TemplateParameterLists,
bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
bool ScopedEnumUsesClassTag, TypeResult UnderlyingType);
@@ -3778,7 +3779,7 @@ public:
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
- AccessSpecifier AS,
+ AccessSpecifier AS, bool IsModulePrivate,
unsigned NumOuterTemplateParamLists,
TemplateParameterList **OuterTemplateParamLists);
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 3a95d1342f..5f9c1910e2 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -313,8 +313,12 @@ void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
std::string S = D->getNameAsString();
D->getUnderlyingType().getAsStringInternal(S, Policy);
- if (!Policy.SuppressSpecifiers)
+ if (!Policy.SuppressSpecifiers) {
Out << "typedef ";
+
+ if (D->isModulePrivate())
+ Out << "__module_private__ ";
+ }
Out << S;
}
@@ -324,6 +328,8 @@ void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
Out << "enum ";
if (D->isScoped()) {
if (D->isScopedUsingClassTag())
@@ -347,6 +353,8 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
}
void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
Out << D->getKindName();
if (D->getIdentifier())
Out << ' ' << D;
@@ -376,8 +384,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
case SC_Auto: case SC_Register: llvm_unreachable("invalid for functions");
}
- if (D->isInlineSpecified()) Out << "inline ";
+ if (D->isInlineSpecified()) Out << "inline ";
if (D->isVirtualAsWritten()) Out << "virtual ";
+ if (D->isModulePrivate()) Out << "__module_private__ ";
}
PrintingPolicy SubPolicy(Policy);
@@ -558,6 +567,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
if (!Policy.SuppressSpecifiers && D->isMutable())
Out << "mutable ";
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
std::string Name = D->getNameAsString();
D->getType().getAsStringInternal(Name, Policy);
@@ -586,6 +597,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
Out << "__thread ";
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
std::string Name = D->getNameAsString();
QualType T = D->getType();
@@ -650,6 +663,8 @@ void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
}
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ if (!Policy.SuppressSpecifiers && D->isModulePrivate())
+ Out << "__module_private__ ";
Out << D->getKindName();
if (D->getIdentifier())
Out << ' ' << D;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index c5cedeafbb..3c692cc577 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1502,6 +1502,7 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) {
/// type-specifier declaration-specifiers[opt]
/// [C99] function-specifier declaration-specifiers[opt]
/// [GNU] attributes declaration-specifiers[opt]
+/// [Clang] '__module_private__' declaration-specifiers[opt]
///
/// storage-class-specifier: [C99 6.7.1]
/// 'typedef'
@@ -1952,6 +1953,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
break;
+ // Modules
+ case tok::kw___module_private__:
+ isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID);
+ break;
+
// constexpr
case tok::kw_constexpr:
isInvalid = DS.SetConstexprSpec(Loc, PrevSpec, DiagID);
@@ -2844,7 +2850,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
unsigned DiagID;
Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK,
StartLoc, SS, Name, NameLoc, attrs.getList(),
- AS,
+ AS, DS.isModulePrivateSpecified(),
MultiTemplateParamsArg(Actions),
Owned, IsDependent, IsScopedEnum,
IsScopedUsingClassTag, BaseType);
@@ -3207,6 +3213,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_register:
case tok::kw___thread:
+ // Modules
+ case tok::kw___module_private__:
+
// type-specifiers
case tok::kw_short:
case tok::kw_long:
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 0dacf3c8a3..63f32d094b 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1193,6 +1193,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Declaration or definition of a class type
TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
SS, Name, NameLoc, attrs.getList(), AS,
+ DS.isModulePrivateSpecified(),
TParams, Owned, IsDependent, false,
false, clang::TypeResult());
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index f0f4c2c729..9b2ea90ba1 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -553,7 +553,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___fastcall) ||
Tok.is(tok::kw___thiscall) ||
- Tok.is(tok::kw___unaligned))
+ Tok.is(tok::kw___unaligned))
return TPResult::True(); // attributes indicate declaration
TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
if (TPR != TPResult::Ambiguous())
@@ -712,7 +712,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___stdcall:
case tok::kw___fastcall:
case tok::kw___thiscall:
- case tok::kw___unaligned:
+ case tok::kw___unaligned:
case tok::kw___vector:
case tok::kw___pixel:
return TPResult::False();
@@ -871,6 +871,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw_virtual:
case tok::kw_explicit:
+ // Modules
+ case tok::kw___module_private__:
+
// type-specifier:
// simple-type-specifier
// class-specifier
@@ -906,7 +909,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
case tok::kw___ptr64:
case tok::kw___ptr32:
case tok::kw___forceinline:
- case tok::kw___unaligned:
+ case tok::kw___unaligned:
return TPResult::True();
// Borland
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index c388192bfe..55964d5006 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -695,6 +695,18 @@ bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
return false;
}
+bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID) {
+ if (isModulePrivateSpecified()) {
+ PrevSpec = "__module_private__";
+ DiagID = diag::ext_duplicate_declspec;
+ return true;
+ }
+
+ ModulePrivateLoc = Loc;
+ return false;
+}
+
bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
// 'constexpr constexpr' is ok.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0961aa9a72..881fb86a78 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3803,6 +3803,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setThreadSpecified(true);
}
+ if (D.getDeclSpec().isModulePrivateSpecified())
+ NewVD->setModulePrivate();
+
// Set the lexical context. If the declarator has a C++ scope specifier, the
// lexical context will be different from the semantic context.
NewVD->setLexicalDeclContext(CurContext);
@@ -4686,6 +4689,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_constexpr_dtor);
}
+ // If __module_private__ was specified, mark the function accordingly.
+ if (D.getDeclSpec().isModulePrivateSpecified()) {
+ NewFD->setModulePrivate();
+ if (FunctionTemplate)
+ FunctionTemplate->setModulePrivate();
+ }
// Filter out previous declarations that don't match the scope.
FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
@@ -6970,6 +6979,9 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
return NewTD;
}
+ if (D.getDeclSpec().isModulePrivateSpecified())
+ NewTD->setModulePrivate();
+
// C++ [dcl.typedef]p8:
// If the typedef declaration defines an unnamed class (or
// enum), the first typedef-name declared by the declaration
@@ -7111,6 +7123,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr, AccessSpecifier AS,
+ bool IsModulePrivate,
MultiTemplateParamsArg TemplateParameterLists,
bool &OwnedDecl, bool &IsDependent,
bool ScopedEnum, bool ScopedEnumUsesClassTag,
@@ -7150,6 +7163,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
SS, Name, NameLoc, Attr,
TemplateParams, AS,
+ IsModulePrivate,
TemplateParameterLists.size() - 1,
(TemplateParameterList**) TemplateParameterLists.release());
return Result.get();
@@ -7712,6 +7726,9 @@ CreateNewDecl:
AddMsStructLayoutForRecord(RD);
}
+ if (IsModulePrivate)
+ New->setModulePrivate();
+
// If this is a specialization of a member class (of a class template),
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e8725eacf2..3acbb98ebd 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -9471,6 +9471,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc,
SS, Name, NameLoc, Attr,
TemplateParams, AS_public,
+ /*IsModulePrivate=*/false,
TempParamLists.size() - 1,
(TemplateParameterList**) TempParamLists.release()).take();
} else {
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index c3d155cc84..db60f17921 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -811,7 +811,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
TemplateParameterList *TemplateParams,
- AccessSpecifier AS,
+ AccessSpecifier AS, bool IsModulePrivate,
unsigned NumOuterTemplateParamLists,
TemplateParameterList** OuterTemplateParamLists) {
assert(TemplateParams && TemplateParams->size() > 0 &&
@@ -1000,6 +1000,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
NewClass, PrevClassTemplate);
NewClass->setDescribedClassTemplate(NewTemplate);
+ if (IsModulePrivate)
+ NewTemplate->setModulePrivate();
+
// Build the type for the class template declaration now.
QualType T = NewTemplate->getInjectedClassNameSpecialization();
T = Context.getInjectedClassNameType(NewClass, T);
@@ -4931,14 +4934,14 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// -- The argument list of the specialization shall not be identical
// to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
- << (TUK == TUK_Definition)
- << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
+ << (TUK == TUK_Definition)
+ << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
Attr,
TemplateParams,
- AS_none,
+ AS_none, /*IsModulePrivate=*/false,
TemplateParameterLists.size() - 1,
(TemplateParameterList**) TemplateParameterLists.release());
}
@@ -5973,6 +5976,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
bool IsDependent = false;
Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference,
KWLoc, SS, Name, NameLoc, Attr, AS_none,
+ /*IsModulePrivate=*/false,
MultiTemplateParamsArg(*this, 0, 0),
Owned, IsDependent, false, false,
TypeResult());
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index e33085dbd7..1abf0d39ee 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -248,6 +248,7 @@ void ASTDeclReader::VisitDecl(Decl *D) {
D->setReferenced(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
D->setPCHLevel(Record[Idx++] + (F.Kind <= MK_PCH));
+ D->ModulePrivate = Record[Idx++];
}
void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) {
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index b5d4d8f313..d94f783aa9 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -156,6 +156,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) {
Record.push_back(D->isReferenced());
Record.push_back(D->getAccess());
Record.push_back(D->getPCHLevel());
+ Record.push_back(D->ModulePrivate);
}
void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
@@ -185,6 +186,7 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) {
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclTypedefAbbrev();
@@ -234,6 +236,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
@@ -257,6 +260,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclRecordAbbrev();
@@ -473,6 +477,7 @@ void ASTDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getPCHLevel() == 0 &&
+ !D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasExtInfo() &&
D->getDeclName())
@@ -611,6 +616,7 @@ void ASTDeclWriter::VisitFieldDecl(FieldDecl *D) {
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getPCHLevel() == 0 &&
+ !D->isModulePrivate() &&
!D->getBitWidth() &&
!D->hasInClassInitializer() &&
!D->hasExtInfo() &&
@@ -663,6 +669,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
!D->isInvalidDecl() &&
!D->isReferenced() &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
D->getPCHLevel() == 0 &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
@@ -704,6 +711,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
!D->isImplicit() &&
!D->isUsed(false) &&
D->getAccess() == AS_none &&
+ !D->isModulePrivate() &&
D->getPCHLevel() == 0 &&
D->getStorageClass() == 0 &&
!D->hasCXXDirectInitializer() && // Can params have this ever?
@@ -1265,6 +1273,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1296,6 +1305,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1330,6 +1340,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1375,6 +1386,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1414,6 +1426,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1462,6 +1475,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
@@ -1487,6 +1501,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
+ Abv->Add(BitCodeAbbrevOp(0)); // ModulePrivate
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
diff --git a/test/Modules/module-private.cpp b/test/Modules/module-private.cpp
new file mode 100644
index 0000000000..419946e8a5
--- /dev/null
+++ b/test/Modules/module-private.cpp
@@ -0,0 +1,56 @@
+// RUN: mkdir -p %t
+// RUN: %clang_cc1 -x c++ -emit-module -o %t/left.pcm %s -D MODULE_LEFT
+// RUN: %clang_cc1 -x c++ -emit-module -o %t/right.pcm %s -D MODULE_RIGHT
+// RUN: %clang_cc1 -I %t %s -verify
+
+#if defined(MODULE_LEFT)
+
+__module_private__ struct HiddenStruct {
+};
+
+
+int &f0(int);
+
+template<typename T>
+__module_private__ void f1(T*);
+
+template<typename T>
+__module_private__ class vector {
+};
+
+vector<float> vec_float;
+
+typedef __module_private__ int Integer;
+
+#elif defined(MODULE_RIGHT)
+__module_private__ double &f0(double);
+
+__module_private__ int hidden_var;
+
+inline void test_f0_in_right() {
+ double &dr = f0(hidden_var);
+}
+#else
+__import_module__ left;
+__import_module__ right;
+
+void test() {
+ int &ir = f0(1.0); // okay: f0() from 'right' is not visible
+}
+
+int test_broken() {
+ HiddenStruct hidden; // expected-error{{use of undeclared identifier 'HiddenStruct'}}
+
+ Integer i; // expected-error{{use of undeclared identifier 'Integer'}}
+
+ int *ip = 0;
+ f1(ip); // expected-error{{use of undeclared identifier 'f1'}}
+
+ vector<int> vec; // expected-error{{use of undeclared identifier 'vector'}} \
+ // expected-error{{expected '(' for function-style cast or type construction}} \
+ // expected-error{{use of undeclared identifier 'vec'}}
+
+ return hidden_var; // expected-error{{use of undeclared identifier 'hidden_var'}}
+}
+
+#endif