aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-01-09 17:30:44 +0000
committerDouglas Gregor <dgregor@apple.com>2012-01-09 17:30:44 +0000
commitc6c8e0ec96bb64f1b9f543d7c8317c6090f80a30 (patch)
tree39aea2b30aebc4a42f967293a8e28181ab8fc20e
parentc02d62f0b82c144f7db2a71c3b4565de8c6163e5 (diff)
Implement redeclaration merging for namespaces defined in distinct
modules. Teach name lookup into namespaces to search in each of the merged DeclContexts as well as the (now-primary) DeclContext. This supports the common case where two different modules put something into the same namespace. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147778 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclBase.h17
-rw-r--r--lib/AST/DeclBase.cpp13
-rw-r--r--lib/Serialization/ASTReader.cpp42
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp23
-rw-r--r--test/Modules/Inputs/namespaces-left.h16
-rw-r--r--test/Modules/Inputs/namespaces-right.h11
-rw-r--r--test/Modules/namespaces.cpp21
7 files changed, 127 insertions, 16 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index b84ac85082..2964d8cf0a 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -514,6 +514,12 @@ protected:
NextInContextAndBits.setInt(Bits);
}
+ /// \brief Set the owning module ID.
+ void setOwningModuleID(unsigned ID) {
+ assert(isFromASTFile() && "Only works on a deserialized declaration");
+ *((unsigned*)this - 2) = ID;
+ }
+
public:
/// \brief Determine the availability of the given declaration.
@@ -573,7 +579,16 @@ public:
return *((const unsigned*)this - 1);
return 0;
}
-
+
+ /// \brief Retrieve the global ID of the module that owns this particular
+ /// declaration.
+ unsigned getOwningModuleID() const {
+ if (isFromASTFile())
+ return *((const unsigned*)this - 2);
+
+ return 0;
+ }
+
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 0312cfbc4a..6a508dfcbe 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -45,14 +45,17 @@ void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
unsigned ID,
unsigned Size) {
// Allocate an extra 8 bytes worth of storage, which ensures that the
- // resulting pointer will still be 8-byte aligned. At present, we're only
- // using the latter 4 bytes of this storage.
+ // resulting pointer will still be 8-byte aligned.
void *Start = Context.Allocate(Size + 8);
void *Result = (char*)Start + 8;
- // Store the global declaration ID
- unsigned *IDPtr = (unsigned*)Result - 1;
- *IDPtr = ID;
+ unsigned *PrefixPtr = (unsigned *)Result - 2;
+
+ // Zero out the first 4 bytes; this is used to store the owning module ID.
+ PrefixPtr[0] = 0;
+
+ // Store the global declaration ID in the second 4 bytes.
+ PrefixPtr[1] = ID;
return Result;
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index df158599de..fa21bf5fdb 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -4808,15 +4808,17 @@ namespace {
/// declaration context.
class DeclContextNameLookupVisitor {
ASTReader &Reader;
+ llvm::SmallVectorImpl<const DeclContext *> &Contexts;
const DeclContext *DC;
DeclarationName Name;
SmallVectorImpl<NamedDecl *> &Decls;
public:
DeclContextNameLookupVisitor(ASTReader &Reader,
- const DeclContext *DC, DeclarationName Name,
+ SmallVectorImpl<const DeclContext *> &Contexts,
+ DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Decls)
- : Reader(Reader), DC(DC), Name(Name), Decls(Decls) { }
+ : Reader(Reader), Contexts(Contexts), Name(Name), Decls(Decls) { }
static bool visit(ModuleFile &M, void *UserData) {
DeclContextNameLookupVisitor *This
@@ -4824,11 +4826,20 @@ namespace {
// Check whether we have any visible declaration information for
// this context in this module.
- ModuleFile::DeclContextInfosMap::iterator Info
- = M.DeclContextInfos.find(This->DC);
- if (Info == M.DeclContextInfos.end() || !Info->second.NameLookupTableData)
- return false;
+ ModuleFile::DeclContextInfosMap::iterator Info;
+ bool FoundInfo = false;
+ for (unsigned I = 0, N = This->Contexts.size(); I != N; ++I) {
+ Info = M.DeclContextInfos.find(This->Contexts[I]);
+ if (Info != M.DeclContextInfos.end() &&
+ Info->second.NameLookupTableData) {
+ FoundInfo = true;
+ break;
+ }
+ }
+ if (!FoundInfo)
+ return false;
+
// Look for this name within this module.
ASTDeclContextNameLookupTable *LookupTable =
(ASTDeclContextNameLookupTable*)Info->second.NameLookupTableData;
@@ -4870,7 +4881,24 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclContext::lookup_iterator(0));
SmallVector<NamedDecl *, 64> Decls;
- DeclContextNameLookupVisitor Visitor(*this, DC, Name, Decls);
+
+ // Compute the declaration contexts we need to look into. Multiple such
+ // declaration contexts occur when two declaration contexts from disjoint
+ // modules get merged, e.g., when two namespaces with the same name are
+ // independently defined in separate modules.
+ SmallVector<const DeclContext *, 2> Contexts;
+ Contexts.push_back(DC);
+
+ if (DC->isNamespace()) {
+ MergedDeclsMap::iterator Merged
+ = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ if (Merged != MergedDecls.end()) {
+ for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
+ Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
+ }
+ }
+
+ DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
SetExternalVisibleDeclsForName(DC, Name, Decls);
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 56e2d085e3..ffd768a94d 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -369,6 +369,9 @@ void ASTDeclReader::VisitDecl(Decl *D) {
// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
if (unsigned SubmoduleID = readSubmoduleID(Record, Idx)) {
+ // Store the owning submodule ID in the declaration.
+ D->setOwningModuleID(SubmoduleID);
+
// Module-private declarations are never visible, so there is no work to do.
if (!D->isModulePrivate()) {
if (Module *Owner = Reader.getSubmodule(SubmoduleID)) {
@@ -972,7 +975,8 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
D->setInline(Record[Idx++]);
D->LocStart = ReadSourceLocation(Record, Idx);
D->RBraceLoc = ReadSourceLocation(Record, Idx);
-
+ mergeRedeclarable(D, Redecl);
+
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
@@ -1232,7 +1236,7 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
RedeclKind Kind = (RedeclKind)Record[Idx++];
// Determine the first declaration ID.
- DeclID FirstDeclID;
+ DeclID FirstDeclID = 0;
switch (Kind) {
case FirstDeclaration: {
FirstDeclID = ThisDeclID;
@@ -1489,7 +1493,7 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
enum RedeclKind { FirstDeclaration = 0, FirstInFile, PointsToPrevious };
RedeclKind Kind = (RedeclKind)Record[Idx++];
- DeclID FirstDeclID;
+ DeclID FirstDeclID = 0;
switch (Kind) {
case FirstDeclaration:
FirstDeclID = ThisDeclID;
@@ -1545,6 +1549,13 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
D->RedeclLink
= typename Redeclarable<T>::PreviousDeclLink(ExistingCanon);
+ // When we merge a namespace, update its pointer to the first namespace.
+ if (NamespaceDecl *Namespace
+ = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+ Namespace->AnonOrFirstNamespaceAndInline.setPointer(
+ static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
+ }
+
// Don't introduce DCanon into the set of pending declaration chains.
Redecl.suppress();
@@ -1719,6 +1730,12 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
VarX->getASTContext().hasSameType(VarX->getType(), VarY->getType());
}
+ // Namespaces with the same name and inlinedness match.
+ if (NamespaceDecl *NamespaceX = dyn_cast<NamespaceDecl>(X)) {
+ NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y);
+ return NamespaceX->isInline() == NamespaceY->isInline();
+ }
+
// FIXME: Many other cases to implement.
return false;
}
diff --git a/test/Modules/Inputs/namespaces-left.h b/test/Modules/Inputs/namespaces-left.h
index 85e6d7dc60..6835cda0c4 100644
--- a/test/Modules/Inputs/namespaces-left.h
+++ b/test/Modules/Inputs/namespaces-left.h
@@ -9,3 +9,19 @@ namespace N1 {
namespace N2 {
float& f(float);
}
+
+
+
+
+
+namespace N5 {
+ int &f(int);
+}
+
+namespace N6 {
+ int &f(int);
+}
+
+namespace N7 {
+ int &f(int);
+}
diff --git a/test/Modules/Inputs/namespaces-right.h b/test/Modules/Inputs/namespaces-right.h
index 23c88bdbe9..0afef073c3 100644
--- a/test/Modules/Inputs/namespaces-right.h
+++ b/test/Modules/Inputs/namespaces-right.h
@@ -16,3 +16,14 @@ namespace N3 {
double& f(double);
}
+namespace N5 {
+ double &f(double);
+}
+
+namespace N6 {
+ double &f(double);
+}
+
+namespace N7 {
+ double &f(double);
+}
diff --git a/test/Modules/namespaces.cpp b/test/Modules/namespaces.cpp
index 75557ba4c1..e1a8d6e8b0 100644
--- a/test/Modules/namespaces.cpp
+++ b/test/Modules/namespaces.cpp
@@ -1,6 +1,10 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify
+namespace N6 {
+ char &f(char);
+}
+
@import namespaces_left;
@import namespaces_right;
@@ -13,3 +17,20 @@ void test() {
double &dr1 = N2::f(1.0);
double &dr2 = N3::f(1.0);
}
+
+// Test namespaces merged without a common first declaration.
+namespace N5 {
+ char &f(char);
+}
+
+void testMerged() {
+ int &ir1 = N5::f(17);
+ int &ir2 = N6::f(17);
+ int &ir3 = N7::f(17);
+ double &fr1 = N5::f(1.0);
+ double &fr2 = N6::f(1.0);
+ double &fr3 = N7::f(1.0);
+ char &cr1 = N5::f('a');
+ char &cr2 = N6::f('b');
+}
+