]> granicus.if.org Git - clang/commitdiff
Improve the performance of resolving a lookup result. We usually don't need to
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 22 Aug 2015 21:37:34 +0000 (21:37 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 22 Aug 2015 21:37:34 +0000 (21:37 +0000)
pick the most recent declaration, and we can often tell which declaration is
more recent without walking the redeclaration chain. Do so when possible.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@245794 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaLookup.cpp

index bf67ae29c1d46b7cba18135ef0ca4430b0b857be..1c6256eb91797d0cc2caba88a971508c443bcb69 100644 (file)
@@ -356,7 +356,7 @@ static DeclContext *getContextForScopeMatching(Decl *D) {
 
 /// \brief Determine whether \p D is a better lookup result than \p Existing,
 /// given that they declare the same entity.
-static bool isPreferredLookupResult(Sema::LookupNameKind Kind,
+static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind,
                                     NamedDecl *D, NamedDecl *Existing) {
   // When looking up redeclarations of a using declaration, prefer a using
   // shadow declaration over any other declaration of the same entity.
@@ -376,13 +376,46 @@ static bool isPreferredLookupResult(Sema::LookupNameKind Kind,
     return false;
   }
 
-  // If D is newer than Existing, prefer it.
+  // Pick the function with more default arguments.
+  // FIXME: In the presence of ambiguous default arguments, we should keep both,
+  //        so we can diagnose the ambiguity if the default argument is needed.
+  //        See C++ [over.match.best]p3.
+  if (auto *DFD = dyn_cast<FunctionDecl>(DUnderlying)) {
+    auto *EFD = cast<FunctionDecl>(EUnderlying);
+    unsigned DMin = DFD->getMinRequiredArguments();
+    unsigned EMin = EFD->getMinRequiredArguments();
+    // If D has more default arguments, it is preferred.
+    if (DMin != EMin)
+      return DMin < EMin;
+  }
+
+  // Pick the template with more default template arguments.
+  if (auto *DTD = dyn_cast<TemplateDecl>(DUnderlying)) {
+    auto *ETD = cast<TemplateDecl>(EUnderlying);
+    unsigned DMin = DTD->getTemplateParameters()->getMinRequiredArguments();
+    unsigned EMin = ETD->getTemplateParameters()->getMinRequiredArguments();
+    // If D has more default arguments, it is preferred.
+    if (DMin != EMin)
+      return DMin < EMin;
+  }
+
+  // For most kinds of declaration, it doesn't really matter which one we pick.
+  if (!isa<FunctionDecl>(DUnderlying) && !isa<VarDecl>(DUnderlying)) {
+    // If the existing declaration is hidden, prefer the new one. Otherwise,
+    // keep what we've got.
+    return !S.isVisible(Existing);
+  }
+
+  // Pick the newer declaration; it might have a more precise type.
   for (Decl *Prev = DUnderlying->getPreviousDecl(); Prev;
        Prev = Prev->getPreviousDecl())
     if (Prev == EUnderlying)
       return true;
-
   return false;
+
+  // If the existing declaration is hidden, prefer the new one. Otherwise,
+  // keep what we've got.
+  return !S.isVisible(Existing);
 }
 
 /// Resolves the result kind of this lookup.
@@ -462,7 +495,7 @@ void LookupResult::resolveKind() {
     if (ExistingI) {
       // This is not a unique lookup result. Pick one of the results and
       // discard the other.
-      if (isPreferredLookupResult(getLookupKind(), Decls[I],
+      if (isPreferredLookupResult(getSema(), getLookupKind(), Decls[I],
                                   Decls[*ExistingI]))
         Decls[*ExistingI] = Decls[I];
       Decls[I] = Decls[--N];