From f5c9f9fd6f5e2850b9b0f19283430245b696c6e5 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 7 Jan 2012 09:11:48 +0000 Subject: [PATCH] Switch NamespaceDecl from its own hand-rolled redeclaration chain over to Redeclarable, so that we benefit from the improveed redeclaration deserialization and merging logic provided by Redeclarable. Otherwise, no functionality change. As a drive-by fix, collapse the "inline" bit into the low bit of the original namespace/anonymous namespace, saving 8 bytes per NamespaceDecl on x86_64. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147729 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 117 +++++++++---------- include/clang/AST/DeclBase.h | 30 +++-- lib/AST/ASTImporter.cpp | 4 +- lib/AST/DeclBase.cpp | 32 +++-- lib/AST/DeclCXX.cpp | 28 +++-- lib/Sema/SemaDeclCXX.cpp | 156 ++++++++++++------------- lib/Sema/SemaLookup.cpp | 6 +- lib/Serialization/ASTReaderDecl.cpp | 46 +++++--- lib/Serialization/ASTWriterDecl.cpp | 9 +- test/Modules/Inputs/module.map | 12 ++ test/Modules/Inputs/namespaces-left.h | 11 ++ test/Modules/Inputs/namespaces-right.h | 18 +++ test/Modules/Inputs/namespaces-top.h | 11 ++ test/Modules/namespaces.cpp | 15 +++ 14 files changed, 286 insertions(+), 209 deletions(-) create mode 100644 test/Modules/Inputs/namespaces-left.h create mode 100644 test/Modules/Inputs/namespaces-right.h create mode 100644 test/Modules/Inputs/namespaces-top.h create mode 100644 test/Modules/namespaces.cpp diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 569608a60b..3b04c25ce5 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -351,9 +351,10 @@ public: }; /// NamespaceDecl - Represent a C++ namespace. -class NamespaceDecl : public NamedDecl, public DeclContext { +class NamespaceDecl : public NamedDecl, public DeclContext, + public Redeclarable +{ virtual void anchor(); - bool IsInline : 1; /// LocStart - The starting location of the source range, pointing /// to either the namespace or the inline keyword. @@ -361,44 +362,37 @@ class NamespaceDecl : public NamedDecl, public DeclContext { /// RBraceLoc - The ending location of the source range. SourceLocation RBraceLoc; - // For extended namespace definitions: - // - // namespace A { int x; } - // namespace A { int y; } - // - // there will be one NamespaceDecl for each declaration. - // NextNamespace points to the next extended declaration. - // OrigNamespace points to the original namespace declaration. - // OrigNamespace of the first namespace decl points to its anonymous namespace - LazyDeclPtr NextNamespace; - - /// \brief A pointer to either the original namespace definition for - /// this namespace (if the boolean value is false) or the anonymous - /// namespace that lives just inside this namespace (if the boolean - /// value is true). - /// - /// We can combine these two notions because the anonymous namespace - /// must only be stored in one of the namespace declarations (so all - /// of the namespace declarations can find it). We therefore choose - /// the original namespace declaration, since all of the namespace - /// declarations have a link directly to it; the original namespace - /// declaration itself only needs to know that it is the original - /// namespace declaration (which the boolean indicates). - llvm::PointerIntPair OrigOrAnonNamespace; - - NamespaceDecl(DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id) - : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), - IsInline(false), LocStart(StartLoc), RBraceLoc(), - NextNamespace(), OrigOrAnonNamespace(0, true) { } + /// \brief A pointer to either the anonymous namespace that lives just inside + /// this namespace or to the first namespace in the chain (the latter case + /// only when this is not the first in the chain), along with a + /// boolean value indicating whether this is an inline namespace. + llvm::PointerIntPair AnonOrFirstNamespaceAndInline; + + NamespaceDecl(DeclContext *DC, bool Inline, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl); + + typedef Redeclarable redeclarable_base; + virtual NamespaceDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } public: static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id); + bool Inline, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl); static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID); + typedef redeclarable_base::redecl_iterator redecl_iterator; + redecl_iterator redecls_begin() const { + return redeclarable_base::redecls_begin(); + } + redecl_iterator redecls_end() const { + return redeclarable_base::redecls_end(); + } + /// \brief Returns true if this is an anonymous namespace declaration. /// /// For example: @@ -414,62 +408,55 @@ public: /// \brief Returns true if this is an inline namespace declaration. bool isInline() const { - return IsInline; + return AnonOrFirstNamespaceAndInline.getInt(); } /// \brief Set whether this is an inline namespace declaration. void setInline(bool Inline) { - IsInline = Inline; + AnonOrFirstNamespaceAndInline.setInt(Inline); } - /// \brief Return the next extended namespace declaration or null if there - /// is none. - NamespaceDecl *getNextNamespace(); - const NamespaceDecl *getNextNamespace() const { - return const_cast(this)->getNextNamespace(); + /// \brief Get the original (first) namespace declaration. + NamespaceDecl *getOriginalNamespace() { + return getCanonicalDecl(); } - /// \brief Set the next extended namespace declaration. - void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; } - /// \brief Get the original (first) namespace declaration. - NamespaceDecl *getOriginalNamespace() const { - if (OrigOrAnonNamespace.getInt()) - return const_cast(this); - - return OrigOrAnonNamespace.getPointer(); + const NamespaceDecl *getOriginalNamespace() const { + return getCanonicalDecl(); } /// \brief Return true if this declaration is an original (first) declaration /// of the namespace. This is false for non-original (subsequent) namespace /// declarations and anonymous namespaces. bool isOriginalNamespace() const { - return getOriginalNamespace() == this; - } - - /// \brief Set the original (first) namespace declaration. - void setOriginalNamespace(NamespaceDecl *ND) { - if (ND != this) { - OrigOrAnonNamespace.setPointer(ND); - OrigOrAnonNamespace.setInt(false); - } + return isFirstDeclaration(); } + /// \brief Retrieve the anonymous namespace nested inside this namespace, + /// if any. NamespaceDecl *getAnonymousNamespace() const { - return getOriginalNamespace()->OrigOrAnonNamespace.getPointer(); + return getOriginalNamespace()->AnonOrFirstNamespaceAndInline.getPointer(); } void setAnonymousNamespace(NamespaceDecl *D) { - assert(!D || D->isAnonymousNamespace()); - assert(!D || D->getParent()->getRedeclContext() == this); - getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D); + getOriginalNamespace()->AnonOrFirstNamespaceAndInline.setPointer(D); } - virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); } + /// Retrieves the canonical declaration of this namespace. + NamespaceDecl *getCanonicalDecl() { + if (isFirstDeclaration()) + return this; + + return AnonOrFirstNamespaceAndInline.getPointer(); + } const NamespaceDecl *getCanonicalDecl() const { - return getOriginalNamespace(); + if (isFirstDeclaration()) + return this; + + return AnonOrFirstNamespaceAndInline.getPointer(); } - + virtual SourceRange getSourceRange() const { return SourceRange(LocStart, RBraceLoc); } diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index f52f5ad334..b84ac85082 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -1082,24 +1082,30 @@ public: /// inline, its enclosing namespace, recursively. bool InEnclosingNamespaceSetOf(const DeclContext *NS) const; - /// getNextContext - If this is a DeclContext that may have other - /// DeclContexts that are semantically connected but syntactically - /// different, such as C++ namespaces, this routine retrieves the - /// next DeclContext in the link. Iteration through the chain of - /// DeclContexts should begin at the primary DeclContext and - /// continue until this function returns NULL. For example, given: - /// @code + /// \\brief Collects all of the declaration contexts that are semantically + /// connected to this declaration context. + /// + /// For declaration contexts that have multiple semantically connected but + /// syntactically distinct contexts, such as C++ namespaces, this routine + /// retrieves the complete set of such declaration contexts in source order. + /// For example, given: + /// + /// \code /// namespace N { /// int x; /// } /// namespace N { /// int y; /// } - /// @endcode - /// The first occurrence of namespace N will be the primary - /// DeclContext. Its getNextContext will return the second - /// occurrence of namespace N. - DeclContext *getNextContext(); + /// \endcode + /// + /// The \c Contexts parameter will contain both definitions of N. + /// + /// \param Contexts Will be cleared and set to the set of declaration + /// contexts that are semanticaly connected to this declaration context, + /// in source order, including this context (which may be the only result, + /// for non-namespace contexts). + void collectAllContexts(llvm::SmallVectorImpl &Contexts); /// decl_iterator - Iterates through the declarations stored /// within this context. diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 82307e8e98..10f5a206d5 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -2083,8 +2083,10 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { NamespaceDecl *ToNamespace = MergeWithNamespace; if (!ToNamespace) { ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC, + D->isInline(), Importer.Import(D->getLocStart()), - Loc, Name.getAsIdentifierInfo()); + Loc, Name.getAsIdentifierInfo(), + /*PrevDecl=*/0); ToNamespace->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToNamespace); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 3fc507ebdb..0312cfbc4a 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -839,15 +839,21 @@ DeclContext *DeclContext::getPrimaryContext() { } } -DeclContext *DeclContext::getNextContext() { - switch (DeclKind) { - case Decl::Namespace: - // Return the next namespace - return static_cast(this)->getNextNamespace(); - - default: - return 0; +void +DeclContext::collectAllContexts(llvm::SmallVectorImpl &Contexts){ + Contexts.clear(); + + if (DeclKind != Decl::Namespace) { + Contexts.push_back(this); + return; } + + NamespaceDecl *Self = static_cast(this); + for (NamespaceDecl *N = Self->getMostRecentDeclaration(); N; + N = N->getPreviousDeclaration()) + Contexts.push_back(N); + + std::reverse(Contexts.begin(), Contexts.end()); } std::pair @@ -1067,15 +1073,17 @@ void DeclContext::addDeclInternal(Decl *D) { /// declarations in DCtx (and any other contexts linked to it or /// transparent contexts nested within it). void DeclContext::buildLookup(DeclContext *DCtx) { - for (; DCtx; DCtx = DCtx->getNextContext()) { - for (decl_iterator D = DCtx->decls_begin(), - DEnd = DCtx->decls_end(); + llvm::SmallVector Contexts; + DCtx->collectAllContexts(Contexts); + for (unsigned I = 0, N = Contexts.size(); I != N; ++I) { + for (decl_iterator D = Contexts[I]->decls_begin(), + DEnd = Contexts[I]->decls_end(); D != DEnd; ++D) { // Insert this declaration into the lookup structure, but only // if it's semantically in its decl context. During non-lazy // lookup building, this is implicitly enforced by addDecl. if (NamedDecl *ND = dyn_cast(*D)) - if (D->getDeclContext() == DCtx) + if (D->getDeclContext() == Contexts[I]) makeDeclVisibleInContextImpl(ND, false); // If this declaration is itself a transparent declaration context or diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ba369bbe99..f820e9b57f 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1767,20 +1767,30 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { void NamespaceDecl::anchor() { } +NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl) + : NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace), + LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline) +{ + setPreviousDeclaration(PrevDecl); + + if (PrevDecl) + AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace()); +} + NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id) { - return new (C) NamespaceDecl(DC, StartLoc, IdLoc, Id); + bool Inline, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl) { + return new (C) NamespaceDecl(DC, Inline, StartLoc, IdLoc, Id, PrevDecl); } NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(NamespaceDecl)); - return new (Mem) NamespaceDecl(0, SourceLocation(), SourceLocation(), 0); -} - -NamespaceDecl *NamespaceDecl::getNextNamespace() { - return dyn_cast_or_null( - NextNamespace.get(getASTContext().getExternalSource())); + return new (Mem) NamespaceDecl(0, false, SourceLocation(), SourceLocation(), + 0, 0); } void NamespaceAliasDecl::anchor() { } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 56b526b1d7..44c84f3679 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5531,17 +5531,13 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc; // For anonymous namespace, take the location of the left brace. SourceLocation Loc = II ? IdentLoc : LBrace; - NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, - StartLoc, Loc, II); - Namespc->setInline(InlineLoc.isValid()); - + bool IsInline = InlineLoc.isValid(); + bool IsInvalid = false; + bool IsStd = false; + bool AddToKnown = false; Scope *DeclRegionScope = NamespcScope->getParent(); - ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); - - if (const VisibilityAttr *Attr = Namespc->getAttr()) - PushNamespaceVisibilityAttr(Attr); - + NamespaceDecl *PrevNS = 0; if (II) { // C++ [namespace.def]p2: // The identifier in an original-namespace-definition shall not @@ -5555,11 +5551,11 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // look through using directives, just look for any ordinary names. const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Member | - Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | - Decl::IDNS_Namespace; + Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag | + Decl::IDNS_Namespace; NamedDecl *PrevDecl = 0; for (DeclContext::lookup_result R - = CurContext->getRedeclContext()->lookup(II); + = CurContext->getRedeclContext()->lookup(II); R.first != R.second; ++R.first) { if ((*R.first)->getIdentifierNamespace() & IDNS) { PrevDecl = *R.first; @@ -5567,100 +5563,90 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, } } - if (NamespaceDecl *OrigNS = dyn_cast_or_null(PrevDecl)) { + PrevNS = dyn_cast_or_null(PrevDecl); + + if (PrevNS) { // This is an extended namespace definition. - if (Namespc->isInline() != OrigNS->isInline()) { + if (IsInline != PrevNS->isInline()) { // inline-ness must match - if (OrigNS->isInline()) { + if (PrevNS->isInline()) { // The user probably just forgot the 'inline', so suggest that it // be added back. - Diag(Namespc->getLocation(), - diag::warn_inline_namespace_reopened_noninline) + Diag(Loc, diag::warn_inline_namespace_reopened_noninline) << FixItHint::CreateInsertion(NamespaceLoc, "inline "); } else { - Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) - << Namespc->isInline(); + Diag(Loc, diag::err_inline_namespace_mismatch) + << IsInline; } - Diag(OrigNS->getLocation(), diag::note_previous_definition); - - // Recover by ignoring the new namespace's inline status. - Namespc->setInline(OrigNS->isInline()); - } - - // Attach this namespace decl to the chain of extended namespace - // definitions. - OrigNS->setNextNamespace(Namespc); - Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace()); - - // Remove the previous declaration from the scope. - if (DeclRegionScope->isDeclScope(OrigNS)) { - IdResolver.RemoveDecl(OrigNS); - DeclRegionScope->RemoveDecl(OrigNS); - } + Diag(PrevNS->getLocation(), diag::note_previous_definition); + + IsInline = PrevNS->isInline(); + } } else if (PrevDecl) { // This is an invalid name redefinition. - Diag(Namespc->getLocation(), diag::err_redefinition_different_kind) - << Namespc->getDeclName(); + Diag(Loc, diag::err_redefinition_different_kind) + << II; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - Namespc->setInvalidDecl(); + IsInvalid = true; // Continue on to push Namespc as current DeclContext and return it. - } else if (II->isStr("std") && + } else if (II->isStr("std") && CurContext->getRedeclContext()->isTranslationUnit()) { // This is the first "real" definition of the namespace "std", so update // our cache of the "std" namespace to point at this definition. - if (NamespaceDecl *StdNS = getStdNamespace()) { - // We had already defined a dummy namespace "std". Link this new - // namespace definition to the dummy namespace "std". - StdNS->setNextNamespace(Namespc); - StdNS->setLocation(IdentLoc); - Namespc->setOriginalNamespace(StdNS->getOriginalNamespace()); - } - - // Make our StdNamespace cache point at the first real definition of the - // "std" namespace. - StdNamespace = Namespc; - - // Add this instance of "std" to the set of known namespaces - KnownNamespaces[Namespc] = false; - } else if (!Namespc->isInline()) { - // Since this is an "original" namespace, add it to the known set of - // namespaces if it is not an inline namespace. - KnownNamespaces[Namespc] = false; + PrevNS = getStdNamespace(); + IsStd = true; + AddToKnown = !IsInline; + } else { + // We've seen this namespace for the first time. + AddToKnown = !IsInline; } - - PushOnScopeChains(Namespc, DeclRegionScope); } else { // Anonymous namespaces. - assert(Namespc->isAnonymousNamespace()); - - // Link the anonymous namespace into its parent. - NamespaceDecl *PrevDecl; + + // Determine whether the parent already has an anonymous namespace. DeclContext *Parent = CurContext->getRedeclContext(); if (TranslationUnitDecl *TU = dyn_cast(Parent)) { - PrevDecl = TU->getAnonymousNamespace(); - TU->setAnonymousNamespace(Namespc); + PrevNS = TU->getAnonymousNamespace(); } else { NamespaceDecl *ND = cast(Parent); - PrevDecl = ND->getAnonymousNamespace(); - ND->setAnonymousNamespace(Namespc); + PrevNS = ND->getAnonymousNamespace(); } - // Link the anonymous namespace with its previous declaration. - if (PrevDecl) { - assert(PrevDecl->isAnonymousNamespace()); - assert(!PrevDecl->getNextNamespace()); - Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace()); - PrevDecl->setNextNamespace(Namespc); + if (PrevNS && IsInline != PrevNS->isInline()) { + // inline-ness must match + Diag(Loc, diag::err_inline_namespace_mismatch) + << IsInline; + Diag(PrevNS->getLocation(), diag::note_previous_definition); + IsInvalid = true; + + // Recover by ignoring the new namespace's inline status. + IsInline = PrevNS->isInline(); + } + } + + NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline, + StartLoc, Loc, II, PrevNS); + + ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); - if (Namespc->isInline() != PrevDecl->isInline()) { - // inline-ness must match - Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) - << Namespc->isInline(); - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - Namespc->setInvalidDecl(); - // Recover by ignoring the new namespace's inline status. - Namespc->setInline(PrevDecl->isInline()); - } + // FIXME: Should we be merging attributes? + if (const VisibilityAttr *Attr = Namespc->getAttr()) + PushNamespaceVisibilityAttr(Attr); + + if (IsStd) + StdNamespace = Namespc; + if (AddToKnown) + KnownNamespaces[Namespc] = false; + + if (II) { + PushOnScopeChains(Namespc, DeclRegionScope); + } else { + // Link the anonymous namespace into its parent. + DeclContext *Parent = CurContext->getRedeclContext(); + if (TranslationUnitDecl *TU = dyn_cast(Parent)) { + TU->setAnonymousNamespace(Namespc); + } else { + cast(Parent)->setAnonymousNamespace(Namespc); } CurContext->addDecl(Namespc); @@ -5681,7 +5667,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // declarations semantically contained within an anonymous // namespace internal linkage. - if (!PrevDecl) { + if (!PrevNS) { UsingDirectiveDecl* UD = UsingDirectiveDecl::Create(Context, CurContext, /* 'using' */ LBrace, @@ -5740,8 +5726,10 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() { // The "std" namespace has not yet been defined, so build one implicitly. StdNamespace = NamespaceDecl::Create(Context, Context.getTranslationUnitDecl(), + /*Inline=*/false, SourceLocation(), SourceLocation(), - &PP.getIdentifierTable().get("std")); + &PP.getIdentifierTable().get("std"), + /*PrevDecl=*/0); getStdNamespace()->setImplicit(true); } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 984184b9c9..eab1517b65 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2740,8 +2740,10 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, Result.getSema().ForceDeclarationOfImplicitMembers(Class); // Enumerate all of the results in this context. - for (DeclContext *CurCtx = Ctx->getPrimaryContext(); CurCtx; - CurCtx = CurCtx->getNextContext()) { + llvm::SmallVector Contexts; + Ctx->collectAllContexts(Contexts); + for (unsigned I = 0, N = Contexts.size(); I != N; ++I) { + DeclContext *CurCtx = Contexts[I]; for (DeclContext::decl_iterator D = CurCtx->decls_begin(), DEnd = CurCtx->decls_end(); D != DEnd; ++D) { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 24ac976c10..6e73388da1 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -967,17 +967,22 @@ void ASTDeclReader::VisitLabelDecl(LabelDecl *D) { void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { + RedeclarableResult Redecl = VisitRedeclarable(D); VisitNamedDecl(D); - D->IsInline = Record[Idx++]; + D->setInline(Record[Idx++]); D->LocStart = ReadSourceLocation(Record, Idx); D->RBraceLoc = ReadSourceLocation(Record, Idx); - D->NextNamespace = Record[Idx++]; - - bool IsOriginal = Record[Idx++]; - // FIXME: Modules will likely have trouble with pointing directly at - // the original namespace. - D->OrigOrAnonNamespace.setInt(IsOriginal); - D->OrigOrAnonNamespace.setPointer(ReadDeclAs(Record, Idx)); + + if (Redecl.getFirstID() == ThisDeclID) { + // FIXME: If there's already an anonymous namespace, do we merge it with + // this one? Or do we, when loading modules, just forget about anonymous + // namespace entirely? + D->setAnonymousNamespace(ReadDeclAs(Record, Idx)); + } else { + // Link this namespace back to the first declaration, which has already + // been deserialized. + D->AnonOrFirstNamespaceAndInline.setPointer(D->getFirstDeclaration()); + } } void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { @@ -1772,6 +1777,8 @@ void ASTDeclReader::attachPreviousDecl(Decl *D, Decl *previous) { ID->RedeclLink.setPointer(cast(previous)); } else if (ObjCProtocolDecl *PD = dyn_cast(D)) { PD->RedeclLink.setPointer(cast(previous)); + } else if (NamespaceDecl *ND = dyn_cast(D)) { + ND->RedeclLink.setPointer(cast(previous)); } else { RedeclarableTemplateDecl *TD = cast(D); TD->CommonOrPrev = cast(previous); @@ -1801,6 +1808,10 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) { PD->RedeclLink = Redeclarable::LatestDeclLink( cast(Latest)); + } else if (NamespaceDecl *ND = dyn_cast(D)) { + ND->RedeclLink + = Redeclarable::LatestDeclLink( + cast(Latest)); } else { RedeclarableTemplateDecl *TD = cast(D); TD->getCommonPtr()->Latest = cast(Latest); @@ -2216,6 +2227,8 @@ static Decl *getPreviousDecl(Decl *D) { return ID->getPreviousDeclaration(); if (ObjCProtocolDecl *PD = dyn_cast(D)) return PD->getPreviousDeclaration(); + if (NamespaceDecl *ND = dyn_cast(D)) + return ND->getPreviousDeclaration(); return cast(D)->getPreviousDeclaration(); } @@ -2234,7 +2247,9 @@ static Decl *getMostRecentDecl(Decl *D) { return ID->getMostRecentDeclaration(); if (ObjCProtocolDecl *PD = dyn_cast(D)) return PD->getMostRecentDeclaration(); - + if (NamespaceDecl *ND = dyn_cast(D)) + return ND->getMostRecentDeclaration(); + return cast(D)->getMostRecentDeclaration(); } @@ -2446,15 +2461,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { NamespaceDecl *Anon = Reader.ReadDeclAs(ModuleFile, Record, Idx); - // Guard against these being loaded out of original order. Don't use - // getNextNamespace(), since it tries to access the context and can't in - // the middle of deserialization. - if (!Anon->NextNamespace) { - if (TranslationUnitDecl *TU = dyn_cast(D)) - TU->setAnonymousNamespace(Anon); - else - cast(D)->OrigOrAnonNamespace.setPointer(Anon); - } + if (TranslationUnitDecl *TU = dyn_cast(D)) + TU->setAnonymousNamespace(Anon); + else + cast(D)->setAnonymousNamespace(Anon); break; } diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 7ff1d5aab0..45ce7799fa 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -802,18 +802,14 @@ void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) { void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { + VisitRedeclarable(D); VisitNamedDecl(D); Record.push_back(D->isInline()); Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddSourceLocation(D->getRBraceLoc(), Record); - Writer.AddDeclRef(D->getNextNamespace(), Record); - // Only write one reference--original or anonymous - Record.push_back(D->isOriginalNamespace()); if (D->isOriginalNamespace()) Writer.AddDeclRef(D->getAnonymousNamespace(), Record); - else - Writer.AddDeclRef(D->getOriginalNamespace(), Record); Code = serialization::DECL_NAMESPACE; if (Writer.hasChain() && !D->isOriginalNamespace() && @@ -836,7 +832,8 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { } } - if (Writer.hasChain() && D->isAnonymousNamespace() && !D->getNextNamespace()){ + if (Writer.hasChain() && D->isAnonymousNamespace() && + D == D->getMostRecentDeclaration()) { // This is a most recent reopening of the anonymous namespace. If its parent // is in a previous PCH (or is the TU), mark that parent for update, because // the original namespace always points to the latest re-opening of its diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 640aa3c1f6..2819e62b8f 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -63,3 +63,15 @@ module redecl_merge_bottom { header "redecl-merge-bottom.h" export * } +module namespaces_top { + header "namespaces-top.h" + export * +} +module namespaces_left { + header "namespaces-left.h" + export * +} +module namespaces_right { + header "namespaces-right.h" + export * +} diff --git a/test/Modules/Inputs/namespaces-left.h b/test/Modules/Inputs/namespaces-left.h new file mode 100644 index 0000000000..85e6d7dc60 --- /dev/null +++ b/test/Modules/Inputs/namespaces-left.h @@ -0,0 +1,11 @@ +@import namespaces_top; + +namespace N1 { } + +namespace N1 { + float& f(float); +} + +namespace N2 { + float& f(float); +} diff --git a/test/Modules/Inputs/namespaces-right.h b/test/Modules/Inputs/namespaces-right.h new file mode 100644 index 0000000000..23c88bdbe9 --- /dev/null +++ b/test/Modules/Inputs/namespaces-right.h @@ -0,0 +1,18 @@ +@import namespaces_top; + +namespace N2 { } + +namespace N2 { } + +namespace N2 { } + +namespace N2 { } + +namespace N2 { + double& f(double); +} + +namespace N3 { + double& f(double); +} + diff --git a/test/Modules/Inputs/namespaces-top.h b/test/Modules/Inputs/namespaces-top.h new file mode 100644 index 0000000000..a69f43f183 --- /dev/null +++ b/test/Modules/Inputs/namespaces-top.h @@ -0,0 +1,11 @@ +namespace N1 { + int& f(int); +} + +namespace N2 { + int& f(int); +} + +namespace N3 { + int& f(int); +} diff --git a/test/Modules/namespaces.cpp b/test/Modules/namespaces.cpp new file mode 100644 index 0000000000..75557ba4c1 --- /dev/null +++ b/test/Modules/namespaces.cpp @@ -0,0 +1,15 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify + +@import namespaces_left; +@import namespaces_right; + +void test() { + int &ir1 = N1::f(1); + int &ir2 = N2::f(1); + int &ir3 = N3::f(1); + float &fr1 = N1::f(1.0f); + float &fr2 = N2::f(1.0f); + double &dr1 = N2::f(1.0); + double &dr2 = N3::f(1.0); +} -- 2.40.0