Fixes problem in finding visible convertion functions of a class
where matching conversion types in base classes were still visible.
Plus refactoring and cleanup.
Added a test case.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83485 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index d1aef6a..7408f2f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -285,39 +285,45 @@
   PlainOldData = false;
 }
 
+void
+CXXRecordDecl::collectConversionFunctions(
+                        llvm::SmallPtrSet<QualType, 8>& ConversionsTypeSet) {
+  OverloadedFunctionDecl *TopConversions = getConversionFunctions();
+  for (OverloadedFunctionDecl::function_iterator
+       TFunc = TopConversions->function_begin(),
+       TFuncEnd = TopConversions->function_end();
+       TFunc != TFuncEnd; ++TFunc) {
+    NamedDecl *TopConv = TFunc->get();
+    QualType TConvType;
+    if (FunctionTemplateDecl *TConversionTemplate =
+        dyn_cast<FunctionTemplateDecl>(TopConv))
+      TConvType = 
+        getASTContext().getCanonicalType(
+                    TConversionTemplate->getTemplatedDecl()->getResultType());
+    else 
+      TConvType = 
+        getASTContext().getCanonicalType(
+                      cast<CXXConversionDecl>(TopConv)->getConversionType());
+    ConversionsTypeSet.insert(TConvType);
+  }  
+}
+
 /// getNestedVisibleConversionFunctions - imports unique conversion 
 /// functions from base classes into the visible conversion function
 /// list of the class 'RD'. This is a private helper method.
+/// TopConversionsTypeSet is the set of conversion functions of the class
+/// we are interested in. HiddenConversionTypes is set of conversion functions
+/// of the immediate derived class which  hides the conversion functions found 
+/// in current class.
 void
-CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD) {
+CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
+                const llvm::SmallPtrSet<QualType, 8> &TopConversionsTypeSet,                               
+                const llvm::SmallPtrSet<QualType, 8> &HiddenConversionTypes) {
+  bool inTopClass = (RD == this);
   QualType ClassType = getASTContext().getTypeDeclType(this);
   if (const RecordType *Record = ClassType->getAs<RecordType>()) {
     OverloadedFunctionDecl *Conversions
       = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
-    llvm::SmallPtrSet<QualType, 8> TopConversionsTypeSet;
-    bool inTopClass = (RD == this);
-    if (!inTopClass && 
-        (Conversions->function_begin() != Conversions->function_end())) {
-      // populate the TypeSet with the type of current class's conversions.
-      OverloadedFunctionDecl *TopConversions = RD->getConversionFunctions();
-      for (OverloadedFunctionDecl::function_iterator
-           TFunc = TopConversions->function_begin(),
-           TFuncEnd = TopConversions->function_end();
-           TFunc != TFuncEnd; ++TFunc) {
-        NamedDecl *TopConv = TFunc->get();
-        QualType TConvType;
-        if (FunctionTemplateDecl *TConversionTemplate =
-            dyn_cast<FunctionTemplateDecl>(TopConv))
-          TConvType = 
-            getASTContext().getCanonicalType(
-                      TConversionTemplate->getTemplatedDecl()->getResultType());
-        else 
-          TConvType = 
-            getASTContext().getCanonicalType(
-                        cast<CXXConversionDecl>(TopConv)->getConversionType());
-        TopConversionsTypeSet.insert(TConvType);
-      }
-    }
     
     for (OverloadedFunctionDecl::function_iterator
          Func = Conversions->function_begin(),
@@ -336,7 +342,12 @@
         ConvType = 
           getASTContext().getCanonicalType(
                           cast<CXXConversionDecl>(Conv)->getConversionType());
-      if (inTopClass || !TopConversionsTypeSet.count(ConvType)) {
+      // We only add conversion functions found in the base class if they
+      // are not hidden by those found in HiddenConversionTypes which are
+      // the conversion functions in its derived class.
+      if (inTopClass || 
+          (!TopConversionsTypeSet.count(ConvType) && 
+           !HiddenConversionTypes.count(ConvType)) ) {
         if (FunctionTemplateDecl *ConversionTemplate =
               dyn_cast<FunctionTemplateDecl>(Conv))
           RD->addVisibleConversionFunction(ConversionTemplate);
@@ -350,7 +361,17 @@
        E = vbases_end(); VBase != E; ++VBase) {
     CXXRecordDecl *VBaseClassDecl
       = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
-    VBaseClassDecl->getNestedVisibleConversionFunctions(RD);
+    if (inTopClass)
+      VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
+                                                        TopConversionsTypeSet,
+                                                        TopConversionsTypeSet);
+    else {
+      llvm::SmallPtrSet<QualType, 8> HiddenConversionTypes;
+        collectConversionFunctions(HiddenConversionTypes);
+      VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
+                                                        TopConversionsTypeSet,
+                                                        HiddenConversionTypes);
+    }
   }
   for (CXXRecordDecl::base_class_iterator Base = bases_begin(),
        E = bases_end(); Base != E; ++Base) {
@@ -358,7 +379,17 @@
       continue;
     CXXRecordDecl *BaseClassDecl
       = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-    BaseClassDecl->getNestedVisibleConversionFunctions(RD);
+    if (inTopClass)
+      BaseClassDecl->getNestedVisibleConversionFunctions(RD,
+                                                         TopConversionsTypeSet,
+                                                         TopConversionsTypeSet);
+    else {
+      llvm::SmallPtrSet<QualType, 8> HiddenConversionTypes;
+      collectConversionFunctions(HiddenConversionTypes);
+      BaseClassDecl->getNestedVisibleConversionFunctions(RD,
+                                                         TopConversionsTypeSet,
+                                                         HiddenConversionTypes);
+    }
   }
 }
 
@@ -372,7 +403,10 @@
   // If visible conversion list is already evaluated, return it.
   if (ComputedVisibleConversions)
     return &VisibleConversions;
-  getNestedVisibleConversionFunctions(this);
+  llvm::SmallPtrSet<QualType, 8> TopConversionsTypeSet;
+  collectConversionFunctions(TopConversionsTypeSet);
+  getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
+                                      TopConversionsTypeSet);
   ComputedVisibleConversions = true;
   return &VisibleConversions;
 }