/// indicating the declaration is used.
void markUsed(ASTContext &C);
- /// \brief Whether this declaration was referenced.
+ /// \brief Whether any declaration of this entity was referenced.
bool isReferenced() const;
+ /// \brief Whether this declaration was referenced. This should not be relied
+ /// upon for anything other than debugging.
+ bool isThisDeclarationReferenced() const { return Referenced; }
+
void setReferenced(bool R = true) { Referenced = R; }
/// \brief Whether this declaration is a top-level declaration (function,
OS << " implicit";
if (D->isUsed())
OS << " used";
- else if (D->isReferenced())
+ else if (D->isThisDeclarationReferenced())
OS << " referenced";
if (D->isInvalidDecl())
OS << " invalid";
if (PrimaryContext != this)
return PrimaryContext->lookup(Name);
+ // If this is a namespace, ensure that any later redeclarations of it have
+ // been loaded, since they may add names to the result of this lookup.
+ if (auto *ND = dyn_cast<NamespaceDecl>(this))
+ (void)ND->getMostRecentDecl();
+
if (hasExternalVisibleStorage()) {
if (NeedToReconcileExternalVisibleStorage)
reconcileExternalVisibleStorage();
SubmoduleID OwnerID = Overrides[OI];
// If this macro is not yet visible, remove it from the hidden names list.
+ // It won't be there if we're in the middle of making the owner visible.
Module *Owner = getSubmodule(OwnerID);
- HiddenNames &Hidden = HiddenNamesMap[Owner];
- HiddenMacrosMap::iterator HI = Hidden.HiddenMacros.find(II);
- if (HI != Hidden.HiddenMacros.end()) {
- // Register the macro now so we don't lose it when we re-export.
- PP.appendMacroDirective(II, HI->second->import(PP, ImportLoc));
-
- auto SubOverrides = HI->second->getOverriddenSubmodules();
- Hidden.HiddenMacros.erase(HI);
- removeOverriddenMacros(II, ImportLoc, Ambig, SubOverrides);
+ auto HiddenIt = HiddenNamesMap.find(Owner);
+ if (HiddenIt != HiddenNamesMap.end()) {
+ HiddenNames &Hidden = HiddenIt->second;
+ HiddenMacrosMap::iterator HI = Hidden.HiddenMacros.find(II);
+ if (HI != Hidden.HiddenMacros.end()) {
+ // Register the macro now so we don't lose it when we re-export.
+ PP.appendMacroDirective(II, HI->second->import(PP, ImportLoc));
+
+ auto SubOverrides = HI->second->getOverriddenSubmodules();
+ Hidden.HiddenMacros.erase(HI);
+ removeOverriddenMacros(II, ImportLoc, Ambig, SubOverrides);
+ }
}
// If this macro is already in our list of conflicts, remove it from there.
auto *DC = cast<DeclContext>(D);
DC->getPrimaryContext()->setHasExternalVisibleStorage(true);
auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData;
- // FIXME: There should never be an existing lookup table.
delete LookupTable;
LookupTable = Table;
} else
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
- // Recursively ensure that the decl context itself is complete
- // (in particular, this matters if the decl context is a namespace).
- //
- // FIXME: This should be performed by lookup instead of here.
- cast<Decl>(DC)->getMostRecentDecl();
-
// If this is a named declaration, complete it by looking it up
// within its context.
//
}
void ASTReader::diagnoseOdrViolations() {
+ if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty())
+ return;
+
// Trigger the import of the full definition of each class that had any
// odr-merging problems, so we can produce better diagnostics for them.
- for (auto &Merge : PendingOdrMergeFailures) {
+ // These updates may in turn find and diagnose some ODR failures, so take
+ // ownership of the set first.
+ auto OdrMergeFailures = std::move(PendingOdrMergeFailures);
+ PendingOdrMergeFailures.clear();
+ for (auto &Merge : OdrMergeFailures) {
Merge.first->buildLookup();
Merge.first->decls_begin();
Merge.first->bases_begin();
}
// Issue any pending ODR-failure diagnostics.
- for (auto &Merge : PendingOdrMergeFailures) {
+ for (auto &Merge : OdrMergeFailures) {
// If we've already pointed out a specific problem with this class, don't
// bother issuing a general "something's different" diagnostic.
if (!DiagnosedOdrMergeFailures.insert(Merge.first))
<< Merge.first;
}
}
- PendingOdrMergeFailures.clear();
}
void ASTReader::FinishedDeserializing() {
// Append the stored merged declarations to the merged declarations set.
MergedDeclsMap::iterator Pos = MergedDecls.find(Canon);
if (Pos == MergedDecls.end())
- Pos = MergedDecls.insert(std::make_pair(Canon,
+ Pos = MergedDecls.insert(std::make_pair(Canon,
SmallVector<DeclID, 2>())).first;
Pos->second.append(StoredPos->second.begin(), StoredPos->second.end());
StoredMergedDecls.erase(StoredPos);
-
+
// Sort and uniquify the set of merged declarations.
llvm::array_pod_sort(Pos->second.begin(), Pos->second.end());
Pos->second.erase(std::unique(Pos->second.begin(), Pos->second.end()),
// DeclContext's Name Lookup Table Serialization
//===----------------------------------------------------------------------===//
+/// Determine the declaration that should be put into the name lookup table to
+/// represent the given declaration in this module. This is usually D itself,
+/// but if D was imported and merged into a local declaration, we want the most
+/// recent local declaration instead. The chosen declaration will be the most
+/// recent declaration in any module that imports this one.
+static NamedDecl *getDeclForLocalLookup(NamedDecl *D) {
+ for (Decl *Redecl = D; Redecl; Redecl = Redecl->getPreviousDecl())
+ if (!Redecl->isFromASTFile())
+ return cast<NamedDecl>(Redecl);
+ return D;
+}
+
namespace {
// Trait used for the on-disk hash table used in the method pool.
class ASTDeclContextNameLookupTrait {
LE.write<uint16_t>(Lookup.size());
for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
I != E; ++I)
- LE.write<uint32_t>(Writer.GetDeclRef(*I));
+ LE.write<uint32_t>(Writer.GetDeclRef(getDeclForLocalLookup(*I)));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
[&](DeclarationName Name,
DeclContext::lookup_const_result Result) {
for (auto *Decl : Result)
- GetDeclRef(Decl);
+ GetDeclRef(getDeclForLocalLookup(Decl));
});
}
}
--- /dev/null
+// a
+namespace llvm { class GlobalValue; }
--- /dev/null
+// b
+namespace llvm { class GlobalValue; }
+#include "y.h"
--- /dev/null
+// c1
+#include "a.h"
+#include "b.h"
--- /dev/null
+// c2
+namespace llvm { class GlobalValue; }
--- /dev/null
+module A { header "a.h" export * }
+module B { header "b.h" export * }
+module C {
+ module C2 { header "c2.h" export * }
+ module C1 { header "c1.h" export * }
+}
+module X { header "x.h" export * }
+module Y { header "y.h" export * }
--- /dev/null
+template <class T> class allocator;
+struct X { virtual allocator<char> f(); };
--- /dev/null
+#include "x.h"
+namespace llvm {
+ struct ulittle32_t;
+ extern allocator<ulittle32_t> *x;
+}
--- /dev/null
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -I%S/Inputs/cxx-lookup -verify
+// expected-no-diagnostics
+namespace llvm {}
+#include "c2.h"
+llvm::GlobalValue *p;
N::f<double>(1.0);
N::f<int>();
N::f(); // expected-error {{no matching function}}
- // expected-note@Inputs/cxx-templates-a.h:6 {{couldn't infer template argument}}
- // expected-note@Inputs/cxx-templates-a.h:7 {{requires 1 argument}}
+ // expected-note@Inputs/cxx-templates-b.h:6 {{couldn't infer template argument}}
+ // expected-note@Inputs/cxx-templates-b.h:7 {{requires single argument}}
template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
template_param_kinds_1<int>(); // ok, from cxx-templates-b.h