Switch NamespaceDecl from its own hand-rolled redeclaration chain over

to Redeclarable<NamespaceDecl>, so that we benefit from the improveed
redeclaration deserialization and merging logic provided by
Redeclarable<T>. 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.

llvm-svn: 147729
This commit is contained in:
Douglas Gregor 2012-01-07 09:11:48 +00:00
parent 43a1bd6ac7
commit e57e752b71
14 changed files with 286 additions and 209 deletions

View File

@ -351,9 +351,10 @@ public:
};
/// NamespaceDecl - Represent a C++ namespace.
class NamespaceDecl : public NamedDecl, public DeclContext {
class NamespaceDecl : public NamedDecl, public DeclContext,
public Redeclarable<NamespaceDecl>
{
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 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<NamespaceDecl *, 1, bool> AnonOrFirstNamespaceAndInline;
/// \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<NamespaceDecl *, 1, bool> 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) { }
NamespaceDecl(DeclContext *DC, bool Inline, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
NamespaceDecl *PrevDecl);
typedef Redeclarable<NamespaceDecl> 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<NamespaceDecl *>(this)->getNextNamespace();
}
/// \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<NamespaceDecl *>(this);
NamespaceDecl *getOriginalNamespace() {
return getCanonicalDecl();
}
return OrigOrAnonNamespace.getPointer();
/// \brief Get the original (first) namespace declaration.
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);
}

View File

@ -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<DeclContext *> &Contexts);
/// decl_iterator - Iterates through the declarations stored
/// within this context.

View File

@ -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);

View File

@ -839,15 +839,21 @@ DeclContext *DeclContext::getPrimaryContext() {
}
}
DeclContext *DeclContext::getNextContext() {
switch (DeclKind) {
case Decl::Namespace:
// Return the next namespace
return static_cast<NamespaceDecl*>(this)->getNextNamespace();
default:
return 0;
void
DeclContext::collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts){
Contexts.clear();
if (DeclKind != Decl::Namespace) {
Contexts.push_back(this);
return;
}
NamespaceDecl *Self = static_cast<NamespaceDecl *>(this);
for (NamespaceDecl *N = Self->getMostRecentDeclaration(); N;
N = N->getPreviousDeclaration())
Contexts.push_back(N);
std::reverse(Contexts.begin(), Contexts.end());
}
std::pair<Decl *, Decl *>
@ -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<DeclContext *, 2> 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<NamedDecl>(*D))
if (D->getDeclContext() == DCtx)
if (D->getDeclContext() == Contexts[I])
makeDeclVisibleInContextImpl(ND, false);
// If this declaration is itself a transparent declaration context or

View File

@ -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<NamespaceDecl>(
NextNamespace.get(getASTContext().getExternalSource()));
return new (Mem) NamespaceDecl(0, false, SourceLocation(), SourceLocation(),
0, 0);
}
void NamespaceAliasDecl::anchor() { }

View File

@ -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<VisibilityAttr>())
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<NamespaceDecl>(PrevDecl)) {
PrevNS = dyn_cast_or_null<NamespaceDecl>(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<TranslationUnitDecl>(Parent)) {
PrevDecl = TU->getAnonymousNamespace();
TU->setAnonymousNamespace(Namespc);
PrevNS = TU->getAnonymousNamespace();
} else {
NamespaceDecl *ND = cast<NamespaceDecl>(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<VisibilityAttr>())
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<TranslationUnitDecl>(Parent)) {
TU->setAnonymousNamespace(Namespc);
} else {
cast<NamespaceDecl>(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);
}

View File

@ -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<DeclContext *, 2> 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) {

View File

@ -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<NamespaceDecl>(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<NamespaceDecl>(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<ObjCInterfaceDecl>(previous));
} else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
PD->RedeclLink.setPointer(cast<ObjCProtocolDecl>(previous));
} else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
ND->RedeclLink.setPointer(cast<NamespaceDecl>(previous));
} else {
RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
TD->CommonOrPrev = cast<RedeclarableTemplateDecl>(previous);
@ -1801,6 +1808,10 @@ void ASTDeclReader::attachLatestDecl(Decl *D, Decl *Latest) {
PD->RedeclLink
= Redeclarable<ObjCProtocolDecl>::LatestDeclLink(
cast<ObjCProtocolDecl>(Latest));
} else if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D)) {
ND->RedeclLink
= Redeclarable<NamespaceDecl>::LatestDeclLink(
cast<NamespaceDecl>(Latest));
} else {
RedeclarableTemplateDecl *TD = cast<RedeclarableTemplateDecl>(D);
TD->getCommonPtr()->Latest = cast<RedeclarableTemplateDecl>(Latest);
@ -2216,6 +2227,8 @@ static Decl *getPreviousDecl(Decl *D) {
return ID->getPreviousDeclaration();
if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
return PD->getPreviousDeclaration();
if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D))
return ND->getPreviousDeclaration();
return cast<RedeclarableTemplateDecl>(D)->getPreviousDeclaration();
}
@ -2234,7 +2247,9 @@ static Decl *getMostRecentDecl(Decl *D) {
return ID->getMostRecentDeclaration();
if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
return PD->getMostRecentDeclaration();
if (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D))
return ND->getMostRecentDeclaration();
return cast<RedeclarableTemplateDecl>(D)->getMostRecentDeclaration();
}
@ -2446,15 +2461,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: {
NamespaceDecl *Anon
= Reader.ReadDeclAs<NamespaceDecl>(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<TranslationUnitDecl>(D))
TU->setAnonymousNamespace(Anon);
else
cast<NamespaceDecl>(D)->OrigOrAnonNamespace.setPointer(Anon);
}
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D))
TU->setAnonymousNamespace(Anon);
else
cast<NamespaceDecl>(D)->setAnonymousNamespace(Anon);
break;
}

View File

@ -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

View File

@ -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 *
}

View File

@ -0,0 +1,11 @@
@import namespaces_top;
namespace N1 { }
namespace N1 {
float& f(float);
}
namespace N2 {
float& f(float);
}

View File

@ -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);
}

View File

@ -0,0 +1,11 @@
namespace N1 {
int& f(int);
}
namespace N2 {
int& f(int);
}
namespace N3 {
int& f(int);
}

View File

@ -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);
}