friend class DependentDiagnostic;
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
+ template<decl_iterator (DeclContext::*Begin)() const,
+ decl_iterator (DeclContext::*End)() const>
void buildLookupImpl(DeclContext *DCtx, bool Internal);
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
bool Rediscoverable);
while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
LexicalContext = LexicalContext->getLexicalParent();
- // Let the static local variable inherit its linkage from the nearest
+ // Let the static local variable inherit it's linkage from the nearest
// enclosing function.
if (LexicalContext)
StaticLocalLinkage =
StoredDeclsMap *DeclContext::buildLookup() {
assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
+ // FIXME: Should we keep going if hasExternalVisibleStorage?
if (!LookupPtr.getInt())
return LookupPtr.getPointer();
SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
- buildLookupImpl(Contexts[I], hasExternalVisibleStorage());
+ buildLookupImpl<&DeclContext::decls_begin,
+ &DeclContext::decls_end>(Contexts[I], false);
// We no longer have any lazy decls.
LookupPtr.setInt(false);
/// declarations contained within DCtx, which will either be this
/// DeclContext, a DeclContext linked to it, or a transparent context
/// nested within it.
+template<DeclContext::decl_iterator (DeclContext::*Begin)() const,
+ DeclContext::decl_iterator (DeclContext::*End)() const>
void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
- for (Decl *D : DCtx->noload_decls()) {
+ for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)();
+ I != E; ++I) {
+ Decl *D = *I;
+
// Insert this declaration into the lookup structure, but only if
// it's semantically within its decl context. Any other decls which
// should be found in this context are added eagerly.
// context (recursively).
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
- buildLookupImpl(InnerCtx, Internal);
+ buildLookupImpl<Begin, End>(InnerCtx, Internal);
}
}
if (PrimaryContext != this)
return PrimaryContext->noload_lookup(Name);
- // Note that buildLookups does not trigger any deserialization.
- StoredDeclsMap *Map = buildLookup();
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt()) {
+ // Carefully build the lookup map, without deserializing anything.
+ SmallVector<DeclContext *, 2> Contexts;
+ collectAllContexts(Contexts);
+ for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
+ buildLookupImpl<&DeclContext::noload_decls_begin,
+ &DeclContext::noload_decls_end>(Contexts[I], true);
+
+ // We no longer have any lazy decls.
+ LookupPtr.setInt(false);
+
+ // There may now be names for which we have local decls but are
+ // missing the external decls. FIXME: Just set the hasExternalDecls
+ // flag on those names that have external decls.
+ NeedToReconcileExternalVisibleStorage = true;
+
+ Map = LookupPtr.getPointer();
+ }
+
if (!Map)
return lookup_result();
bool AllowInlineNamespace) const {
Ctx = Ctx->getRedeclContext();
- if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
+ if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
// Ignore the scopes associated within transparent declaration contexts.
while (S->getEntity() && S->getEntity()->isTransparentContext())
S = S->getParent();
if (Visited.visitedContext(Ctx->getPrimaryContext()))
return;
- // Outside C++, lookup results for the TU live on identifiers.
- if (isa<TranslationUnitDecl>(Ctx) &&
- !Result.getSema().getLangOpts().CPlusPlus) {
- auto &S = Result.getSema();
- auto &Idents = S.Context.Idents;
-
- // Ensure all external identifiers are in the identifier table.
- if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) {
- std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
- for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next())
- Idents.get(Name);
- }
-
- // Walk all lookup results in the TU for each identifier.
- for (const auto &Ident : Idents) {
- for (auto I = S.IdResolver.begin(Ident.getValue()),
- E = S.IdResolver.end();
- I != E; ++I) {
- if (S.IdResolver.isDeclInScope(*I, Ctx)) {
- if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
- }
- }
- }
-
- return;
- }
-
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
// Enumerate all of the results in this context.
for (const auto &R : Ctx->lookups()) {
- for (auto *D : R) {
- if (auto *ND = Result.getAcceptableDecl(D)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
+ for (auto *I : R) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(I)) {
+ if ((ND = Result.getAcceptableDecl(ND))) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+ Visited.add(ND);
+ }
}
}
}
}
case EAGERLY_DESERIALIZED_DECLS:
- // FIXME: Skip reading this record if our ASTConsumer doesn't care
- // about "interesting" decls (for instance, if we're building a module).
for (unsigned I = 0, N = Record.size(); I != N; ++I)
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
true);
- // Ensure that we've loaded all potentially-interesting declarations
- // that need to be eagerly loaded.
- for (auto ID : EagerlyDeserializedDecls)
- GetDecl(ID);
- EagerlyDeserializedDecls.clear();
-
while (!InterestingDecls.empty()) {
Decl *D = InterestingDecls.front();
InterestingDecls.pop_front();
void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
this->Consumer = Consumer;
- if (Consumer)
- PassInterestingDeclsToConsumer();
+ if (!Consumer)
+ return;
+
+ for (unsigned I = 0, N = EagerlyDeserializedDecls.size(); I != N; ++I) {
+ // Force deserialization of this decl, which will cause it to be queued for
+ // passing to the consumer.
+ GetDecl(EagerlyDeserializedDecls[I]);
+ }
+ EagerlyDeserializedDecls.clear();
+
+ PassInterestingDeclsToConsumer();
if (DeserializationListener)
DeserializationListener->ReaderInitialized(this);
// RUN: rm -rf %t
// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
-// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-filter SomeTemplate | FileCheck %s --check-prefix=CHECK-DUMP
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump | FileCheck %s --check-prefix=CHECK-DUMP
// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DEARLY_IMPORT
static_assert(Outer<int>::Inner<int>::f() == 1, "");
static_assert(Outer<int>::Inner<int>::g() == 2, "");
-// FIXME: We're too lazy in merging class definitions to find the definition
-// of this function.
-static_assert(MergeTemplateDefinitions<int>::f() == 1, ""); // expected-error {{constant expression}} expected-note {{undefined}}
-// expected-note@cxx-templates-c.h:10 {{here}}
+#ifndef EARLY_IMPORT
+// FIXME: The textual inclusion above shouldn't cause this to fail!
+static_assert(MergeTemplateDefinitions<int>::f() == 1, "");
static_assert(MergeTemplateDefinitions<int>::g() == 2, "");
RedeclaredAsFriend<int> raf1;
MergeSpecializations<char>::explicitly_specialized_in_a spec_in_a_2;
MergeSpecializations<double>::explicitly_specialized_in_b spec_in_b_2;
MergeSpecializations<bool>::explicitly_specialized_in_c spec_in_c_2;
+#endif
MergeAnonUnionMember<> maum_main;
typedef DontWalkPreviousDeclAfterMerging<int> dwpdam_typedef_2;
int x = f() + g();
// expected-note@a.h:5 {{definition has no member 'e2'}}
-// expected-note@b.h:3 {{declaration of 'f' does not match}}
-// expected-note@b.h:1 {{definition has no member 'n'}}
+// expected-note@a.h:3 {{declaration of 'f' does not match}}
+// expected-note@a.h:1 {{definition has no member 'm'}}
// expected-error@b.h:5 {{'E::e2' from module 'b' is not present in definition of 'E' in module 'a'}}
-// expected-error@a.h:3 {{'Y::f' from module 'a' is not present in definition of 'Y' in module 'b'}}
-// expected-error@a.h:2 {{'Y::n' from module 'a' is not present in definition of 'Y' in module 'b'}}
+// expected-error@b.h:3 {{'Y::f' from module 'b' is not present in definition of 'Y' in module 'a'}}
+// expected-error@b.h:2 {{'Y::m' from module 'b' is not present in definition of 'Y' in module 'a'}}
static constexpr int function(); // expected-note {{here}}
};
typedef D::A DB;
-constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{undefined}}
+constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{subexpression}} expected-note {{undefined}}
#endif
@import redecl_add_after_load;
constexpr int merged_struct_function_test = D_test(false);
#ifndef IMPORT_DECLS
// expected-error@-4 {{incomplete}}
-// @-4: definition of D::variable must be emitted, so it gets imported eagerly
+// expected-error@-4 {{constant}} expected-note@-4 {{in call to}}
// expected-error@-4 {{constant}} expected-note@-4 {{in call to}}
#endif