diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 4cb72183690d..786cc24760f9 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/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/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 55f89734e08f..14d811fa674f 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/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/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 5d68a22ffcb9..534aebbf7758 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/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/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index cdd7dbaa6d29..177de65a34fe 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/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/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h index 1a11dfaad827..1fa9066cf2b1 100644 --- a/clang/include/clang/Sema/Lookup.h +++ b/clang/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/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 935fe9947c95..fc2a7f55c495 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/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/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 3a95d1342f71..5f9c1910e249 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/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/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c5cedeafbb3a..3c692cc57710 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/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/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 0dacf3c8a394..63f32d094b92 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/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/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index f0f4c2c72920..9b2ea90ba15c 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/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/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index c388192bfef7..55964d50062e 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0961aa9a721d..881fb86a78eb 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e8725eacf283..3acbb98ebd93 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c3d155cc84f0..db60f179216e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e33085dbd778..1abf0d39eed8 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/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/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index b5d4d8f3132e..d94f783aa96f 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/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/clang/test/Modules/module-private.cpp b/clang/test/Modules/module-private.cpp new file mode 100644 index 000000000000..419946e8a54e --- /dev/null +++ b/clang/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 +__module_private__ void f1(T*); + +template +__module_private__ class vector { +}; + +vector 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 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