aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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');
+}
+