forked from OSchip/llvm-project
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:
parent
43a1bd6ac7
commit
e57e752b71
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() { }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
@import namespaces_top;
|
||||
|
||||
namespace N1 { }
|
||||
|
||||
namespace N1 {
|
||||
float& f(float);
|
||||
}
|
||||
|
||||
namespace N2 {
|
||||
float& f(float);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
namespace N1 {
|
||||
int& f(int);
|
||||
}
|
||||
|
||||
namespace N2 {
|
||||
int& f(int);
|
||||
}
|
||||
|
||||
namespace N3 {
|
||||
int& f(int);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue