]> granicus.if.org Git - clang/commitdiff
Modules: introduce the __module_private__ declaration specifier, which
authorDouglas Gregor <dgregor@apple.com>
Fri, 9 Sep 2011 02:06:17 +0000 (02:06 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 9 Sep 2011 02:06:17 +0000 (02:06 +0000)
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

17 files changed:
include/clang/AST/Decl.h
include/clang/AST/DeclBase.h
include/clang/Basic/TokenKinds.def
include/clang/Sema/DeclSpec.h
include/clang/Sema/Lookup.h
include/clang/Sema/Sema.h
lib/AST/DeclPrinter.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseTentative.cpp
lib/Sema/DeclSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplate.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Modules/module-private.cpp [new file with mode: 0644]

index 4cb72183690da6e5f88e57ae65cd734d3525c818..786cc24760f9c859b5788f852e6b5174173249f6 100644 (file)
@@ -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();
index 55f89734e08fc4565d4b55de352fd16e822a050b..14d811fa674fc9d74e8e741d8e6d98d54a36983f 100644 (file)
@@ -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)
   {
index 5d68a22ffcb9089642ef5c4a571763be4ed0719d..534aebbf775886a379d4587314981e8f8f93b1ba 100644 (file)
@@ -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)
index cdd7dbaa6d2909572796719ace72f1f672c6a60a..177de65a34fe047a126cd79522c40d1da5e209ba 100644 (file)
@@ -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; }
 
index 1a11dfaad82742c3a38df073ba2ca67fe11dabb5..1fa9066cf2b13bdcd10c315b31513b8260775f2d 100644 (file)
@@ -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.
index 935fe9947c9584b41d225d57f7edb3278a140a11..fc2a7f55c495136f257ce05e03f88eeaf685b32a 100644 (file)
@@ -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);
 
index 3a95d1342f7163229d58b1bf1df6840be262d29c..5f9c1910e24964ddd6b5f3ad73847c2d68593053 100644 (file)
@@ -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;
index c5cedeafbb3a5219bd150e59e7ed240de1dee828..3c692cc57710b485427bd278ea236a2ea2ee3d0a 100644 (file)
@@ -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:
index 0dacf3c8a394c108ff4a4f58faa67b1ff6e2004d..63f32d094b9299fb7d69fc7f10e819b05c682042 100644 (file)
@@ -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());
 
index f0f4c2c72920edaf577070193d1f837a9fa83458..9b2ea90ba15c225e67751d882b8318d7cf121139 100644 (file)
@@ -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))\r
+          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:\r
+  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:\r
+  case tok::kw___unaligned:
     return TPResult::True();
 
     // Borland
index c388192bfef72b96326ea97d51646f7d230bac5e..55964d50062e653723884371aabb161ee5a49e05 100644 (file)
@@ -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.
index 0961aa9a721d777d7239596af7875a9d183ce925..881fb86a78eb36e1c0fa11070dd8d7e7dc81333d 100644 (file)
@@ -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))
index e8725eacf2832042410773443aa3997bfc577c08..3acbb98ebd93c29474ea5d94aa7a37b704ad2e38 100644 (file)
@@ -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 {
index c3d155cc84f0ae5be90eaf149e12310f77933dc5..db60f179216e18ba7cedc41f7b6d9fc3768b7a8e 100644 (file)
@@ -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());
index e33085dbd778f83b877b434cc41a6f5424b10cbf..1abf0d39eed81a024adda133d38488f8155d5f72 100644 (file)
@@ -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) {
index b5d4d8f3132e1f9f7d93f6d7d2c6bdb141f7902f..d94f783aa96f7e2e17b22b0c5157ed344b4cc6db 100644 (file)
@@ -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 (file)
index 0000000..419946e
--- /dev/null
@@ -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