/// template defined within it.
llvm::DenseSet<Module*> &getLookupModules();
+ /// \brief Map from the most recent declaration of a namespace to the most
+ /// recent visible declaration of that namespace.
+ llvm::DenseMap<NamedDecl*, NamedDecl*> VisibleNamespaceCache;
+
/// \brief Whether we are in a SFINAE context that is not associated with
/// template instantiation.
///
VisibleModules = std::move(VisibleModulesStack.back());
VisibleModulesStack.pop_back();
VisibleModules.setVisible(Mod, DirectiveLoc);
+ // Leaving a module hides namespace names, so our visible namespace cache
+ // is now out of date.
+ VisibleNamespaceCache.clear();
}
}
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
for (auto RD : D->redecls()) {
+ // Don't bother with extra checks if we already know this one isn't visible.
+ if (RD == D)
+ continue;
+
if (auto ND = dyn_cast<NamedDecl>(RD)) {
// FIXME: This is wrong in the case where the previous declaration is not
// visible in the same scope as D. This needs to be done much more
}
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
+ if (auto *ND = dyn_cast<NamespaceDecl>(D)) {
+ // Namespaces are a bit of a special case: we expect there to be a lot of
+ // redeclarations of some namespaces, all declarations of a namespace are
+ // essentially interchangeable, all declarations are found by name lookup
+ // if any is, and namespaces are never looked up during template
+ // instantiation. So we benefit from caching the check in this case, and
+ // it is correct to do so.
+ auto *Key = ND->getCanonicalDecl();
+ if (auto *Acceptable = getSema().VisibleNamespaceCache.lookup(Key))
+ return Acceptable;
+ auto *Acceptable =
+ isVisible(getSema(), Key) ? Key : findAcceptableDecl(getSema(), Key);
+ if (Acceptable)
+ getSema().VisibleNamespaceCache.insert(std::make_pair(Key, Acceptable));
+ return Acceptable;
+ }
+
return findAcceptableDecl(getSema(), D);
}