Implement delegating constructors partially.

This successfully performs constructor lookup and verifies that a
delegating initializer is the only initializer present.

This does not perform loop detection in the initialization, but it also
doesn't codegen delegating constructors at all, so this won't cause
runtime infinite loops yet.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126552 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 1656a7e..45108c3 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1148,13 +1148,16 @@
 /// @endcode
 class CXXCtorInitializer {
   /// \brief Either the base class name (stored as a TypeSourceInfo*), an normal
-  /// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being 
-  /// initialized.
-  llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *>
+  /// field (FieldDecl), anonymous field (IndirectFieldDecl*), or target
+  /// constructor (CXXConstructorDecl*) being initialized.
+  llvm::PointerUnion4<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *,
+                      CXXConstructorDecl *>
     Initializee;
   
   /// \brief The source location for the field name or, for a base initializer
-  /// pack expansion, the location of the ellipsis.
+  /// pack expansion, the location of the ellipsis. In the case of a delegating
+  /// constructor, it will still include the type's source location as the
+  /// Initializee points to the CXXConstructorDecl (to allow loop detection).
   SourceLocation MemberOrEllipsisLocation;
   
   /// \brief The argument used to initialize the base or member, which may
@@ -1199,11 +1202,17 @@
                      SourceLocation MemberLoc, SourceLocation L, Expr *Init,
                      SourceLocation R);
 
+  /// CXXCtorInitializer - Creates a new anonymous field initializer.
   explicit
   CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member,
                      SourceLocation MemberLoc, SourceLocation L, Expr *Init,
                      SourceLocation R);
 
+  /// CXXCtorInitializer - Creates a new delegating Initializer.
+  explicit
+  CXXCtorInitializer(ASTContext &Context, SourceLocation D, SourceLocation L,
+                     CXXConstructorDecl *Target, Expr *Init, SourceLocation R);
+
   /// \brief Creates a new member initializer that optionally contains 
   /// array indices used to describe an elementwise initialization.
   static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member,
@@ -1227,6 +1236,12 @@
     return Initializee.is<IndirectFieldDecl*>();
   }
 
+  /// isDelegatingInitializer - Returns true when this initializer is creating
+  /// a delegating constructor.
+  bool isDelegatingInitializer() const {
+    return Initializee.is<CXXConstructorDecl *>();
+  }
+
   /// \brief Determine whether this initializer is a pack expansion.
   bool isPackExpansion() const { 
     return isBaseInitializer() && MemberOrEllipsisLocation.isValid(); 
@@ -1284,6 +1299,13 @@
       return 0;
   }
 
+  CXXConstructorDecl *getTargetConstructor() const {
+    if (isDelegatingInitializer())
+      return Initializee.get<CXXConstructorDecl*>();
+    else
+      return 0;
+  }
+
   SourceLocation getMemberLocation() const { 
     return MemberOrEllipsisLocation;
   }
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index a9fb2da..4b3b335 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -798,8 +798,8 @@
 def err_init_conversion_failed : Error<
   "cannot initialize %select{a variable|a parameter|return object|an "
   "exception object|a member subobject|an array element|a new value|a value|a "
-  "base class|a vector element}0 of type %1 with an %select{rvalue|lvalue}2 of "
-  "type %3">;
+  "base class|a constructor delegation|a vector element}0 of type %1 with an "
+  "%select{rvalue|lvalue}2 of type %3">;
 
 def err_lvalue_to_rvalue_ref : Error<"rvalue reference to type %0 cannot bind "
   "to lvalue of type %1">;
@@ -969,6 +969,8 @@
   "delegating constructors are permitted only in C++0x">;
 def err_delegation_unimplemented : Error<
   "delegating constructors are not fully implemented">;
+def err_delegating_initializer_alone : Error<
+  "an initializer for a delegating constructor must appear alone">;
   
 // Objective-C++
 def err_objc_decls_may_only_appear_in_global_scope : Error<
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index bdf0d8e..7ccd272 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -64,6 +64,8 @@
     EK_Temporary,
     /// \brief The entity being initialized is a base member subobject.
     EK_Base,
+    /// \brief The initialization is being done by a delegating constructor.
+    EK_Delegation,
     /// \brief The entity being initialized is an element of a vector.
     /// or vector.
     EK_VectorElement,
@@ -210,6 +212,11 @@
   static InitializedEntity InitializeBase(ASTContext &Context,
                                           CXXBaseSpecifier *Base,
                                           bool IsInheritedVirtualBase);
+
+  /// \brief Create the initialization entity for a delegated constructor.
+  static InitializedEntity InitializeDelegation(QualType Type) {
+    return InitializedEntity(EK_Delegation, SourceLocation(), Type);
+  }
   
   /// \brief Create the initialization entity for a member subobject.
   static InitializedEntity InitializeMember(FieldDecl *Member,
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index a937398..7a1a9f6 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2818,10 +2818,10 @@
 
   MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo,
                                            Expr **Args, unsigned NumArgs,
+                                           SourceLocation BaseLoc,
                                            SourceLocation RParenLoc,
                                            SourceLocation LParenLoc,
-                                           CXXRecordDecl *ClassDecl,
-                                           SourceLocation EllipsisLoc);
+                                           CXXRecordDecl *ClassDecl);
 
   bool SetCtorInitializers(CXXConstructorDecl *Constructor,
                            CXXCtorInitializer **Initializers,
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 46768c1..1b849a5 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1033,6 +1033,16 @@
 }
 
 CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
+                                       SourceLocation D, SourceLocation L,
+                                       CXXConstructorDecl *Target, Expr *Init,
+                                       SourceLocation R)
+  : Initializee(Target), MemberOrEllipsisLocation(D), Init(Init),
+    LParenLoc(L), RParenLoc(R), IsVirtual(false),
+    IsWritten(false), SourceOrderOrNumArrayIndices(0)
+{
+}
+
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
                                        FieldDecl *Member,
                                        SourceLocation MemberLoc,
                                        SourceLocation L, Expr *Init,
@@ -1076,7 +1086,7 @@
 }
 
 SourceLocation CXXCtorInitializer::getSourceLocation() const {
-  if (isAnyMemberInitializer())
+  if (isAnyMemberInitializer() || isDelegatingInitializer())
     return getMemberLocation();
   
   return getBaseClassLoc().getLocalSourceRange().getBegin();
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index f483262..457ae85 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -21,6 +21,7 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/DeclVisitor.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/AST/TypeLoc.h"
@@ -1476,17 +1477,61 @@
 MemInitResult
 Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo,
                                  Expr **Args, unsigned NumArgs,
+                                 SourceLocation NameLoc,
                                  SourceLocation LParenLoc,
                                  SourceLocation RParenLoc,
-                                 CXXRecordDecl *ClassDecl,
-                                 SourceLocation EllipsisLoc) {
+                                 CXXRecordDecl *ClassDecl) {
   SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
   if (!LangOpts.CPlusPlus0x)
     return Diag(Loc, diag::err_delegation_0x_only)
       << TInfo->getTypeLoc().getLocalSourceRange();
 
-  return Diag(Loc, diag::err_delegation_unimplemented)
-    << TInfo->getTypeLoc().getLocalSourceRange();
+  // Initialize the object.
+  InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation(
+                                     QualType(ClassDecl->getTypeForDecl(), 0));
+  InitializationKind Kind =
+    InitializationKind::CreateDirect(NameLoc, LParenLoc, RParenLoc);
+
+  InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs);
+
+  ExprResult DelegationInit =
+    InitSeq.Perform(*this, DelegationEntity, Kind,
+                    MultiExprArg(*this, Args, NumArgs), 0);
+  if (DelegationInit.isInvalid())
+    return true;
+
+  CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get());
+  CXXConstructorDecl *Constructor = ConExpr->getConstructor();
+  assert(Constructor && "Delegating constructor with no target?");
+
+  CheckImplicitConversions(DelegationInit.get(), LParenLoc);
+
+  // C++0x [class.base.init]p7:
+  //   The initialization of each base and member constitutes a
+  //   full-expression.
+  DelegationInit = MaybeCreateExprWithCleanups(DelegationInit);
+  if (DelegationInit.isInvalid())
+    return true;
+
+  // If we are in a dependent context, template instantiation will
+  // perform this type-checking again. Just save the arguments that we
+  // received in a ParenListExpr.
+  // FIXME: This isn't quite ideal, since our ASTs don't capture all
+  // of the information that we have about the base
+  // initializer. However, deconstructing the ASTs is a dicey process,
+  // and this approach is far more likely to get the corner cases right.
+  if (CurContext->isDependentContext()) {
+    ExprResult Init
+      = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args,
+                                          NumArgs, RParenLoc));
+    return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc,
+                                            Constructor, Init.takeAs<Expr>(),
+                                            RParenLoc);
+  }
+
+  return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor,
+                                          DelegationInit.takeAs<Expr>(),
+                                          RParenLoc);
 }
 
 MemInitResult
@@ -1538,9 +1583,8 @@
   if (!Dependent) { 
     if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0),
                                        BaseType))
-      return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs,
-                                        LParenLoc, RParenLoc, ClassDecl,
-                                        EllipsisLoc);
+      return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, BaseLoc,
+                                        LParenLoc, RParenLoc, ClassDecl);
 
     FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, 
                         VirtualBaseSpec);
@@ -2340,10 +2384,19 @@
       if (CheckRedundantInit(*this, Init, Members[Field]) ||
           CheckRedundantUnionInit(*this, Init, MemberUnions))
         HadError = true;
-    } else {
+    } else if (Init->isBaseInitializer()) {
       void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
       if (CheckRedundantInit(*this, Init, Members[Key]))
         HadError = true;
+    } else {
+      assert(Init->isDelegatingInitializer());
+      // This must be the only initializer
+      if (i != 0 || NumMemInits > 1) {
+        Diag(MemInits[0]->getSourceLocation(),
+             diag::err_delegating_initializer_alone)
+          << MemInits[0]->getSourceRange();
+        HadError = true;
+      }
     }
   }
 
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 5882da0..358e5fb 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -1998,6 +1998,7 @@
   case EK_New:
   case EK_Temporary:
   case EK_Base:
+  case EK_Delegation:
   case EK_ArrayElement:
   case EK_VectorElement:
   case EK_BlockElement:
@@ -2020,6 +2021,7 @@
   case EK_New:
   case EK_Temporary:
   case EK_Base:
+  case EK_Delegation:
   case EK_ArrayElement:
   case EK_VectorElement:
   case EK_BlockElement:
@@ -2042,6 +2044,7 @@
   case EK_New:
   case EK_Temporary:
   case EK_Base:
+  case EK_Delegation:
   case EK_ArrayElement:
   case EK_VectorElement:
   case EK_BlockElement:
@@ -3289,6 +3292,7 @@
   case InitializedEntity::EK_New:
   case InitializedEntity::EK_Exception:
   case InitializedEntity::EK_Base:
+  case InitializedEntity::EK_Delegation:
     return Sema::AA_Initializing;
 
   case InitializedEntity::EK_Parameter:
@@ -3325,6 +3329,7 @@
   case InitializedEntity::EK_New:
   case InitializedEntity::EK_Variable:
   case InitializedEntity::EK_Base:
+  case InitializedEntity::EK_Delegation:
   case InitializedEntity::EK_VectorElement:
   case InitializedEntity::EK_Exception:
   case InitializedEntity::EK_BlockElement:
@@ -3346,6 +3351,7 @@
     case InitializedEntity::EK_Result:
     case InitializedEntity::EK_New:
     case InitializedEntity::EK_Base:
+    case InitializedEntity::EK_Delegation:
     case InitializedEntity::EK_VectorElement:
     case InitializedEntity::EK_BlockElement:
       return false;
@@ -3430,6 +3436,7 @@
   case InitializedEntity::EK_Temporary:
   case InitializedEntity::EK_New:
   case InitializedEntity::EK_Base:
+  case InitializedEntity::EK_Delegation:
   case InitializedEntity::EK_VectorElement:
   case InitializedEntity::EK_BlockElement:
     Loc = CurInitExpr->getLocStart();