Implement disambiguation of base class members via a
nested-name-specifier. For example, this allows member access in
diamond-shaped hierarchies like:

  struct Base {
    void Foo();
    int Member;
  };

  struct D1 : public Base {};
  struct D2 : public Base {};

  struct Derived : public D1, public D2 { }

  void Test(Derived d) {
    d.Member = 17; // error: ambiguous cast from Derived to Base
    d.D1::Member = 17; // error: okay, modify D1's Base's Member
  }

Fixes PR5820 and <rdar://problem/7535045>. Also, eliminate some
redundancy between Sema::PerformObjectMemberConversion() and
Sema::PerformObjectArgumentInitialization() -- the latter now calls
the former.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97674 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d9464ad..d8648f2 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -635,7 +635,7 @@
       MemberType = Context.getQualifiedType(MemberType, NewQuals);
 
     MarkDeclarationReferenced(Loc, *FI);
-    PerformObjectMemberConversion(Result, *FI);
+    PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI);
     // FIXME: Might this end up being a qualified name?
     Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
                                       OpLoc, MemberType);
@@ -1357,29 +1357,111 @@
 
 /// \brief Cast member's object to its own class if necessary.
 bool
-Sema::PerformObjectMemberConversion(Expr *&From, NamedDecl *Member) {
-  if (FieldDecl *FD = dyn_cast<FieldDecl>(Member))
-    if (CXXRecordDecl *RD =
-        dyn_cast<CXXRecordDecl>(FD->getDeclContext())) {
-      QualType DestType =
-        Context.getCanonicalType(Context.getTypeDeclType(RD));
-      if (DestType->isDependentType() || From->getType()->isDependentType())
-        return false;
-      QualType FromRecordType = From->getType();
-      QualType DestRecordType = DestType;
-      if (FromRecordType->getAs<PointerType>()) {
-        DestType = Context.getPointerType(DestType);
-        FromRecordType = FromRecordType->getPointeeType();
-      }
-      if (!Context.hasSameUnqualifiedType(FromRecordType, DestRecordType) &&
-          CheckDerivedToBaseConversion(FromRecordType,
-                                       DestRecordType,
-                                       From->getSourceRange().getBegin(),
-                                       From->getSourceRange()))
-        return true;
-      ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
-                        /*isLvalue=*/true);
+Sema::PerformObjectMemberConversion(Expr *&From,
+                                    NestedNameSpecifier *Qualifier,
+                                    NamedDecl *Member) {
+  CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext());
+  if (!RD)
+    return false;
+  
+  QualType DestRecordType;
+  QualType DestType;
+  QualType FromRecordType;
+  QualType FromType = From->getType();
+  bool PointerConversions = false;
+  if (isa<FieldDecl>(Member)) {
+    DestRecordType = Context.getCanonicalType(Context.getTypeDeclType(RD));
+    
+    if (FromType->getAs<PointerType>()) {
+      DestType = Context.getPointerType(DestRecordType);
+      FromRecordType = FromType->getPointeeType();
+      PointerConversions = true;
+    } else {
+      DestType = DestRecordType;
+      FromRecordType = FromType;
     }
+  } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) {
+    if (Method->isStatic())
+      return false;
+    
+    DestType = Method->getThisType(Context);
+    DestRecordType = DestType->getPointeeType();
+    
+    if (FromType->getAs<PointerType>()) {
+      FromRecordType = FromType->getPointeeType();
+      PointerConversions = true;
+    } else {
+      FromRecordType = FromType;
+      DestType = DestRecordType;
+    }
+  } else {
+    // No conversion necessary.
+    return false;
+  }
+  
+  if (DestType->isDependentType() || FromType->isDependentType())
+    return false;
+  
+  // If the unqualified types are the same, no conversion is necessary.
+  if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType))
+    return false;
+  
+  // C++ [class.member.lookup]p8:
+  //   [...] Ambiguities can often be resolved by qualifying a name with its 
+  //   class name.
+  //
+  // If the member was a qualified name and the qualified referred to a
+  // specific base subobject type, we'll cast to that intermediate type
+  // first and then to the object in which the member is declared. That allows
+  // one to resolve ambiguities in, e.g., a diamond-shaped hierarchy such as:
+  //
+  //   class Base { public: int x; };
+  //   class Derived1 : public Base { };
+  //   class Derived2 : public Base { };
+  //   class VeryDerived : public Derived1, public Derived2 { void f(); };
+  //
+  //   void VeryDerived::f() {
+  //     x = 17; // error: ambiguous base subobjects
+  //     Derived1::x = 17; // okay, pick the Base subobject of Derived1
+  //   }
+  QualType IntermediateRecordType;
+  QualType IntermediateType;
+  if (Qualifier) {
+    if (const RecordType *IntermediateRecord
+                           = Qualifier->getAsType()->getAs<RecordType>()) {
+      IntermediateRecordType = QualType(IntermediateRecord, 0);
+      IntermediateType = IntermediateRecordType;
+      if (PointerConversions)
+        IntermediateType = Context.getPointerType(IntermediateType);
+    }
+  }
+  
+  if (!IntermediateType.isNull() &&
+      IsDerivedFrom(FromRecordType, IntermediateRecordType) &&
+      IsDerivedFrom(IntermediateRecordType, DestRecordType)) {
+    if (CheckDerivedToBaseConversion(FromRecordType, IntermediateRecordType,
+                                     From->getSourceRange().getBegin(),
+                                     From->getSourceRange()) ||
+        CheckDerivedToBaseConversion(IntermediateRecordType, DestRecordType,
+                                     From->getSourceRange().getBegin(),
+                                     From->getSourceRange()))
+      return true;
+
+    ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase,
+                      /*isLvalue=*/!PointerConversions);        
+    ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
+                      /*isLvalue=*/!PointerConversions);
+    return false;
+  }
+  
+  if (CheckDerivedToBaseConversion(FromRecordType,
+                                   DestRecordType,
+                                   From->getSourceRange().getBegin(),
+                                   From->getSourceRange()))
+    return true;
+  
+  ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase,
+                    /*isLvalue=*/true);
   return false;
 }
 
@@ -2666,7 +2748,7 @@
     }
 
     MarkDeclarationReferenced(MemberLoc, FD);
-    if (PerformObjectMemberConversion(BaseExpr, FD))
+    if (PerformObjectMemberConversion(BaseExpr, Qualifier, FD))
       return ExprError();
     return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS,
                                  FD, MemberLoc, MemberType));
@@ -6651,7 +6733,7 @@
         Res = BuildAnonymousStructUnionMemberReference(
             OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
       } else {
-        PerformObjectMemberConversion(Res, MemberDecl);
+        PerformObjectMemberConversion(Res, /*Qualifier=*/0, MemberDecl);
         // MemberDecl->getType() doesn't get the right qualifiers, but it
         // doesn't matter here.
         Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,