aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclBase.h27
-rw-r--r--include/clang/AST/DeclContextInternals.h18
-rw-r--r--lib/AST/DeclBase.cpp47
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp15
-rw-r--r--test/Modules/Inputs/namespaces-left.h7
-rw-r--r--test/Modules/Inputs/namespaces-right.h7
-rw-r--r--test/Modules/namespaces.cpp25
7 files changed, 117 insertions, 29 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index efac2fba64..8d9d4ded54 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -928,19 +928,26 @@ class DeclContext {
/// \brief Whether this declaration context also has some external
/// storage that contains additional declarations that are lexically
/// part of this context.
- mutable unsigned ExternalLexicalStorage : 1;
+ mutable bool ExternalLexicalStorage : 1;
/// \brief Whether this declaration context also has some external
/// storage that contains additional declarations that are visible
/// in this context.
- mutable unsigned ExternalVisibleStorage : 1;
+ mutable bool ExternalVisibleStorage : 1;
+
+ /// \brief Whether this declaration context has had external visible
+ /// storage added since the last lookup. In this case, \c LookupPtr's
+ /// invariant may not hold and needs to be fixed before we perform
+ /// another lookup.
+ mutable bool NeedToReconcileExternalVisibleStorage : 1;
/// \brief Pointer to the data structure used to lookup declarations
/// within this context (or a DependentStoredDeclsMap if this is a
/// dependent context), and a bool indicating whether we have lazily
/// omitted any declarations from the map. We maintain the invariant
- /// that, if the map contains an entry for a DeclarationName, then it
- /// contains all relevant entries for that name.
+ /// that, if the map contains an entry for a DeclarationName (and we
+ /// haven't lazily omitted anything), then it contains all relevant
+ /// entries for that name.
mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr;
protected:
@@ -963,10 +970,11 @@ protected:
static std::pair<Decl *, Decl *>
BuildDeclChain(ArrayRef<Decl*> Decls, bool FieldsAlreadyLoaded);
- DeclContext(Decl::Kind K)
- : DeclKind(K), ExternalLexicalStorage(false),
- ExternalVisibleStorage(false), LookupPtr(0, false), FirstDecl(0),
- LastDecl(0) { }
+ DeclContext(Decl::Kind K)
+ : DeclKind(K), ExternalLexicalStorage(false),
+ ExternalVisibleStorage(false),
+ NeedToReconcileExternalVisibleStorage(false), LookupPtr(0, false),
+ FirstDecl(0), LastDecl(0) {}
public:
~DeclContext();
@@ -1497,6 +1505,8 @@ public:
/// declarations visible in this context.
void setHasExternalVisibleStorage(bool ES = true) {
ExternalVisibleStorage = ES;
+ if (ES)
+ NeedToReconcileExternalVisibleStorage = true;
}
/// \brief Determine whether the given declaration is stored in the list of
@@ -1512,6 +1522,7 @@ public:
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
private:
+ void reconcileExternalVisibleStorage();
void LoadLexicalDeclsFromExternalStorage() const;
/// @brief Makes a declaration visible within this context, but
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 6acee7d85c..84f3698d6b 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -97,6 +97,22 @@ public:
== Vec.end() && "list still contains decl");
}
+ /// \brief Remove any declarations which were imported from an external
+ /// AST source.
+ void removeExternalDecls() {
+ if (isNull()) {
+ // Nothing to do.
+ } else if (NamedDecl *Singleton = getAsDecl()) {
+ if (Singleton->isFromASTFile())
+ *this = StoredDeclsList();
+ } else {
+ DeclsTy &Vec = *getAsVector();
+ Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
+ std::mem_fun(&Decl::isFromASTFile)),
+ Vec.end());
+ }
+ }
+
/// getLookupResult - Return an array of all the decls that this list
/// represents.
DeclContext::lookup_result getLookupResult() {
@@ -186,7 +202,7 @@ public:
// All other declarations go at the end of the list, but before any
// tag declarations. But we can be clever about tag declarations
// because there can only ever be one in a scope.
- } else if (Vec.back()->hasTagIdentifierNamespace()) {
+ } else if (!Vec.empty() && Vec.back()->hasTagIdentifierNamespace()) {
NamedDecl *TagD = Vec.back();
Vec.back() = D;
Vec.push_back(TagD);
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 52ecdeb318..3039c95462 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -913,6 +913,24 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
return std::make_pair(FirstNewDecl, PrevDecl);
}
+/// \brief We have just acquired external visible storage, and we already have
+/// built a lookup map. For every name in the map, pull in the new names from
+/// the external storage.
+void DeclContext::reconcileExternalVisibleStorage() {
+ assert(NeedToReconcileExternalVisibleStorage);
+ if (!LookupPtr.getPointer())
+ return;
+
+ NeedToReconcileExternalVisibleStorage = false;
+
+ StoredDeclsMap &Map = *LookupPtr.getPointer();
+ ExternalASTSource *Source = getParentASTContext().getExternalSource();
+ for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) {
+ I->second.removeExternalDecls();
+ Source->FindExternalVisibleDeclsByName(this, I->first);
+ }
+}
+
/// \brief Load the declarations within this lexical storage from an
/// external source.
void
@@ -963,9 +981,8 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
- StoredDeclsList &List = (*Map)[Name];
- assert(List.isNull());
- (void) List;
+ // Add an entry to the map for this name, if it's not already present.
+ (*Map)[Name];
return DeclContext::lookup_result();
}
@@ -975,7 +992,6 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
ArrayRef<NamedDecl*> Decls) {
ASTContext &Context = DC->getParentASTContext();
-
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
@@ -986,6 +1002,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
if (List.isNull())
List.setOnlyValue(*I);
else
+ // FIXME: Need declarationReplaces handling for redeclarations in modules.
List.AddSubsequentDecl(*I);
}
@@ -1145,6 +1162,10 @@ StoredDeclsMap *DeclContext::buildLookup() {
/// DeclContext, a DeclContext linked to it, or a transparent context
/// nested within it.
void DeclContext::buildLookupImpl(DeclContext *DCtx) {
+ // FIXME: If buildLookup is supposed to return a complete map, we should not
+ // bail out in buildLookup if hasExternalVisibleStorage. If it is not required
+ // to include names from PCH and modules, we should use the noload_ iterators
+ // here.
for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end();
I != E; ++I) {
Decl *D = *I;
@@ -1175,11 +1196,17 @@ DeclContext::lookup(DeclarationName Name) {
return PrimaryContext->lookup(Name);
if (hasExternalVisibleStorage()) {
- // If a PCH has a result for this name, and we have a local declaration, we
- // will have imported the PCH result when adding the local declaration.
- // FIXME: For modules, we could have had more declarations added by module
- // imoprts since we saw the declaration of the local name.
- if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ if (NeedToReconcileExternalVisibleStorage)
+ reconcileExternalVisibleStorage();
+
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt())
+ Map = buildLookup();
+
+ // If a PCH/module has a result for this name, and we have a local
+ // declaration, we will have imported the PCH/module result when adding the
+ // local declaration or when reconciling the module.
+ if (Map) {
StoredDeclsMap::iterator I = Map->find(Name);
if (I != Map->end())
return I->second.getLookupResult();
@@ -1224,7 +1251,7 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
- if (Name) {
+ if (Name && !LookupPtr.getInt()) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator Pos = Map->find(Name);
if (Pos != Map->end()) {
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 469b3938ee..c2ace30782 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -2122,12 +2122,18 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// If this declaration is also a declaration context, get the
// offsets for its tables of lexical and visible declarations.
if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ // FIXME: This should really be
+ // DeclContext *LookupDC = DC->getPrimaryContext();
+ // but that can walk the redeclaration chain, which might not work yet.
+ DeclContext *LookupDC = DC;
+ if (isa<NamespaceDecl>(DC))
+ LookupDC = DC->getPrimaryContext();
std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
if (Offsets.first || Offsets.second) {
if (Offsets.first != 0)
DC->setHasExternalLexicalStorage(true);
if (Offsets.second != 0)
- DC->setHasExternalVisibleStorage(true);
+ LookupDC->setHasExternalVisibleStorage(true);
if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets,
Loc.F->DeclContextInfos[DC]))
return 0;
@@ -2139,7 +2145,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
if (I != PendingVisibleUpdates.end()) {
// There are updates. This means the context has external visible
// storage, even if the original stored version didn't.
- DC->setHasExternalVisibleStorage(true);
+ LookupDC->setHasExternalVisibleStorage(true);
DeclContextVisibleUpdates &U = I->second;
for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end();
UI != UE; ++UI) {
@@ -2150,8 +2156,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
PendingVisibleUpdates.erase(I);
}
- if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
- DC->setMustBuildLookupTable();
+ if (!LookupDC->hasExternalVisibleStorage() &&
+ DC->hasExternalLexicalStorage())
+ LookupDC->setMustBuildLookupTable();
}
assert(Idx == Record.size());
diff --git a/test/Modules/Inputs/namespaces-left.h b/test/Modules/Inputs/namespaces-left.h
index 7e9002aea8..bd192afd2e 100644
--- a/test/Modules/Inputs/namespaces-left.h
+++ b/test/Modules/Inputs/namespaces-left.h
@@ -1,5 +1,12 @@
@import namespaces_top;
+float &global(float);
+float &global2(float);
+
+namespace LookupBeforeImport {
+ float &f(float);
+}
+
namespace N1 { }
namespace N1 {
diff --git a/test/Modules/Inputs/namespaces-right.h b/test/Modules/Inputs/namespaces-right.h
index b18aeb4478..77f54ead65 100644
--- a/test/Modules/Inputs/namespaces-right.h
+++ b/test/Modules/Inputs/namespaces-right.h
@@ -1,5 +1,12 @@
@import namespaces_top;
+double &global(double);
+double &global2(double);
+
+namespace LookupBeforeImport {
+ double &f(double);
+}
+
namespace N2 { }
namespace N2 { }
diff --git a/test/Modules/namespaces.cpp b/test/Modules/namespaces.cpp
index 871ae793d3..151e7ea101 100644
--- a/test/Modules/namespaces.cpp
+++ b/test/Modules/namespaces.cpp
@@ -1,9 +1,8 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify
-// Importing modules which add declarations to a pre-existing non-imported
-// overload set does not currently work.
-// XFAIL: *
+int &global(int);
+int &global2(int);
namespace N6 {
char &f(char);
@@ -11,6 +10,13 @@ namespace N6 {
namespace N8 { }
+namespace LookupBeforeImport {
+ int &f(int);
+}
+void testEarly() {
+ int &r = LookupBeforeImport::f(1);
+}
+
@import namespaces_left;
@import namespaces_right;
@@ -18,10 +24,18 @@ void test() {
int &ir1 = N1::f(1);
int &ir2 = N2::f(1);
int &ir3 = N3::f(1);
+ int &ir4 = global(1);
+ int &ir5 = ::global2(1);
float &fr1 = N1::f(1.0f);
float &fr2 = N2::f(1.0f);
+ float &fr3 = global(1.0f);
+ float &fr4 = ::global2(1.0f);
+ float &fr5 = LookupBeforeImport::f(1.0f);
double &dr1 = N2::f(1.0);
double &dr2 = N3::f(1.0);
+ double &dr3 = global(1.0);
+ double &dr4 = ::global2(1.0);
+ double &dr5 = LookupBeforeImport::f(1.0);
}
// Test namespaces merged without a common first declaration.
@@ -54,11 +68,10 @@ void testMergedMerged() {
// Test merging when using anonymous namespaces, which does not
// actually perform any merging.
-// other file: expected-note{{passing argument to parameter here}}
void testAnonymousNotMerged() {
N11::consumeFoo(N11::getFoo()); // expected-error{{cannot initialize a parameter of type 'N11::<anonymous>::Foo *' with an rvalue of type 'N11::<anonymous>::Foo *'}}
N12::consumeFoo(N12::getFoo()); // expected-error{{cannot initialize a parameter of type 'N12::<anonymous>::Foo *' with an rvalue of type 'N12::<anonymous>::Foo *'}}
}
-
-// other file: expected-note{{passing argument to parameter here}}
+// namespaces-right.h: expected-note@60 {{passing argument to parameter here}}
+// namespaces-right.h: expected-note@67 {{passing argument to parameter here}}