]> granicus.if.org Git - clang/commitdiff
Implement delegating constructors partially.
authorSean Hunt <scshunt@csclub.uwaterloo.ca>
Sat, 26 Feb 2011 19:13:13 +0000 (19:13 +0000)
committerSean Hunt <scshunt@csclub.uwaterloo.ca>
Sat, 26 Feb 2011 19:13:13 +0000 (19:13 +0000)
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

include/clang/AST/DeclCXX.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Initialization.h
include/clang/Sema/Sema.h
lib/AST/DeclCXX.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaInit.cpp

index 1656a7e9737c980d4bde329d859a892b2d5f879f..45108c37e0899de64fef5df274345a998a7b3be3 100644 (file)
@@ -1148,13 +1148,16 @@ public:
 /// @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 @@ public:
                      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 @@ public:
     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 @@ public:
       return 0;
   }
 
+  CXXConstructorDecl *getTargetConstructor() const {
+    if (isDelegatingInitializer())
+      return Initializee.get<CXXConstructorDecl*>();
+    else
+      return 0;
+  }
+
   SourceLocation getMemberLocation() const { 
     return MemberOrEllipsisLocation;
   }
index a9fb2da0017658049e351e1272a023a384e43a7f..4b3b335519f11df6f9095f2d46aa5712df5a0548 100644 (file)
@@ -798,8 +798,8 @@ def err_ident_in_pseudo_dtor_not_a_type : Error<
 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 @@ def err_delegation_0x_only : Error<
   "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<
index bdf0d8e7b60242301166c300dcc963ce24c2195f..7ccd27201cfd854b22acdfca5fae814cb4d7ff7c 100644 (file)
@@ -64,6 +64,8 @@ public:
     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 @@ public:
   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,
index a93739892cfe458b8d4fa7552542b12a96a9564a..7a1a9f6b093e642da682984d75098c6e2bc6c2fb 100644 (file)
@@ -2818,10 +2818,10 @@ public:
 
   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,
index 46768c12d87940e845c2e675a4b133cef80cf7bf..1b849a58ad2908d15b2a076e32704cf5a0bb49b6 100644 (file)
@@ -1032,6 +1032,16 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
 {
 }
 
+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,
@@ -1076,7 +1086,7 @@ const Type *CXXCtorInitializer::getBaseClass() const {
 }
 
 SourceLocation CXXCtorInitializer::getSourceLocation() const {
-  if (isAnyMemberInitializer())
+  if (isAnyMemberInitializer() || isDelegatingInitializer())
     return getMemberLocation();
   
   return getBaseClassLoc().getLocalSourceRange().getBegin();
index f483262a8cf589fb13ae30f2b2d66bbabaeac3df..457ae8594131f844d8868274e944ddcc703f4cc6 100644 (file)
@@ -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 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args,
 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 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
   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 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
       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;
+      }
     }
   }
 
index 5882da0eab46050c88e8c7f05303e285e81b96e1..358e5fb5015d8100e34a818c2a5e6e558b7adff5 100644 (file)
@@ -1998,6 +1998,7 @@ DeclarationName InitializedEntity::getName() const {
   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 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
   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 @@ bool InitializedEntity::allowsNRVO() const {
   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 @@ getAssignmentAction(const InitializedEntity &Entity) {
   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 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
   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 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
     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 @@ static ExprResult CopyObject(Sema &S,
   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();