[cfe-commits] [PATCH] Refactor/fix some issues with templates and member initializers

Eli Friedman eli.friedman at gmail.com
Sat Jul 25 18:13:58 PDT 2009


Patch attached.  Fixes all the testcases in PR4621.

This change refactors ActOnMemInitializer so the relevant code can be
called from template instantiation (although I haven't added the
appropriate code).  It adds appropriate checks for arguments with
dependent types.  It also fixes some broken logic for member
initializers which would reject initializing a member with a dependent
type.

I've attached both a regular diff and a diff -w because the latter is
a bit easier to read; I ended up reindenting a lot of the code.

(I decided to submit the patch instead of just committing it because
I'm not sure this is the right approach.)

-Eli
-------------- next part --------------
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp	(revision 77084)
+++ lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -716,28 +716,9 @@
 
     // FIXME: Handle members of an anonymous union.
 
-    if (Member) {
-      CXXConstructorDecl *C = 0;
-      QualType FieldType = Member->getType();
-      if (const ArrayType *Array = Context.getAsArrayType(FieldType))
-        FieldType = Array->getElementType();
-      if (!FieldType->isDependentType() && FieldType->getAsRecordType())
-        C = PerformInitializationByConstructor(
-              FieldType, (Expr **)Args, NumArgs, IdLoc, 
-              SourceRange(IdLoc, RParenLoc), Member->getDeclName(), IK_Direct);
-      else if (NumArgs != 1)
-        return Diag(IdLoc, diag::err_mem_initializer_mismatch) 
-                    << MemberOrBase << SourceRange(IdLoc, RParenLoc);
-      else {
-        Expr * NewExp = (Expr*)Args[0];
-        if (PerformCopyInitialization(NewExp, FieldType, "passing"))
-          return true;
-        Args[0] = NewExp;
-      }
-      // FIXME: Perform direct initialization of the member.
-      return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, 
-                                                      NumArgs, C, IdLoc);
-    }
+    if (Member)
+      return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
+                                    RParenLoc);
   }
   // It didn't name a member, so see if it names a class.
   TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy 
@@ -747,75 +728,124 @@
       << MemberOrBase << SourceRange(IdLoc, RParenLoc);
   
   QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
-  if (!BaseType->isRecordType() && !BaseType->isDependentType())
-    return Diag(IdLoc, diag::err_base_init_does_not_name_class)
-      << BaseType << SourceRange(IdLoc, RParenLoc);
 
-  // C++ [class.base.init]p2:
-  //   [...] Unless the mem-initializer-id names a nonstatic data
-  //   member of the constructor?s class or a direct or virtual base
-  //   of that class, the mem-initializer is ill-formed. A
-  //   mem-initializer-list can initialize a base class using any
-  //   name that denotes that base class type.
-  
-  // First, check for a direct base class.
-  const CXXBaseSpecifier *DirectBaseSpec = 0;
-  for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
-       Base != ClassDecl->bases_end(); ++Base) {
-    if (Context.getCanonicalType(BaseType).getUnqualifiedType() == 
-        Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
-      // We found a direct base of this type. That's what we're
-      // initializing.
-      DirectBaseSpec = &*Base;
-      break;
+  return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc,
+                              RParenLoc, ClassDecl);
+}
+
+Sema::MemInitResult
+Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+                             unsigned NumArgs, SourceLocation IdLoc,
+                             SourceLocation RParenLoc) {
+  bool HasDependentArg = false;
+  for (unsigned i = 0; i < NumArgs; i++)
+    HasDependentArg |= Args[i]->isTypeDependent();
+
+  CXXConstructorDecl *C = 0;
+  QualType FieldType = Member->getType();
+  if (const ArrayType *Array = Context.getAsArrayType(FieldType))
+    FieldType = Array->getElementType();
+  if (FieldType->isDependentType()) {
+    // Can't check init for dependent type.
+  } else if (FieldType->getAsRecordType()) {
+    if (!HasDependentArg)
+      C = PerformInitializationByConstructor(
+            FieldType, (Expr **)Args, NumArgs, IdLoc, 
+            SourceRange(IdLoc, RParenLoc), Member->getDeclName(), IK_Direct);
+  } else if (NumArgs != 1) {
+    return Diag(IdLoc, diag::err_mem_initializer_mismatch) 
+                << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
+  } else if (!HasDependentArg) {
+    Expr *NewExp = (Expr*)Args[0];
+    if (PerformCopyInitialization(NewExp, FieldType, "passing"))
+      return true;
+    Args[0] = NewExp;
+  }
+  // FIXME: Perform direct initialization of the member.
+  return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, 
+                                                  NumArgs, C, IdLoc);
+}
+
+Sema::MemInitResult
+Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
+                           unsigned NumArgs, SourceLocation IdLoc,
+                           SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) {
+  bool HasDependentArg = false;
+  for (unsigned i = 0; i < NumArgs; i++)
+    HasDependentArg |= Args[i]->isTypeDependent();
+
+  if (!BaseType->isDependentType()) {
+    if (!BaseType->isRecordType())
+      return Diag(IdLoc, diag::err_base_init_does_not_name_class)
+        << BaseType << SourceRange(IdLoc, RParenLoc);
+
+    // C++ [class.base.init]p2:
+    //   [...] Unless the mem-initializer-id names a nonstatic data
+    //   member of the constructor?s class or a direct or virtual base
+    //   of that class, the mem-initializer is ill-formed. A
+    //   mem-initializer-list can initialize a base class using any
+    //   name that denotes that base class type.
+    
+    // First, check for a direct base class.
+    const CXXBaseSpecifier *DirectBaseSpec = 0;
+    for (CXXRecordDecl::base_class_const_iterator Base =
+         ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) {
+      if (Context.getCanonicalType(BaseType).getUnqualifiedType() == 
+          Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
+        // We found a direct base of this type. That's what we're
+        // initializing.
+        DirectBaseSpec = &*Base;
+        break;
+      }
     }
-  }
-  
-  // Check for a virtual base class.
-  // FIXME: We might be able to short-circuit this if we know in advance that
-  // there are no virtual bases.
-  const CXXBaseSpecifier *VirtualBaseSpec = 0;
-  if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
-    // We haven't found a base yet; search the class hierarchy for a
-    // virtual base class.
-    BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
-                    /*DetectVirtual=*/false);
-    if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
-      for (BasePaths::paths_iterator Path = Paths.begin(); 
-           Path != Paths.end(); ++Path) {
-        if (Path->back().Base->isVirtual()) {
-          VirtualBaseSpec = Path->back().Base;
-          break;
+    
+    // Check for a virtual base class.
+    // FIXME: We might be able to short-circuit this if we know in advance that
+    // there are no virtual bases.
+    const CXXBaseSpecifier *VirtualBaseSpec = 0;
+    if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
+      // We haven't found a base yet; search the class hierarchy for a
+      // virtual base class.
+      BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+                      /*DetectVirtual=*/false);
+      if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
+        for (BasePaths::paths_iterator Path = Paths.begin(); 
+             Path != Paths.end(); ++Path) {
+          if (Path->back().Base->isVirtual()) {
+            VirtualBaseSpec = Path->back().Base;
+            break;
+          }
         }
       }
     }
+
+    // C++ [base.class.init]p2:
+    //   If a mem-initializer-id is ambiguous because it designates both
+    //   a direct non-virtual base class and an inherited virtual base
+    //   class, the mem-initializer is ill-formed.
+    if (DirectBaseSpec && VirtualBaseSpec)
+      return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
+        << BaseType << SourceRange(IdLoc, RParenLoc);
+    // C++ [base.class.init]p2:
+    // Unless the mem-initializer-id names a nonstatic data membeer of the
+    // constructor's class ot a direst or virtual base of that class, the
+    // mem-initializer is ill-formed.
+    if (!DirectBaseSpec && !VirtualBaseSpec)
+      return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
+      << BaseType << ClassDecl->getNameAsCString()
+      << SourceRange(IdLoc, RParenLoc);
   }
 
-  // C++ [base.class.init]p2:
-  //   If a mem-initializer-id is ambiguous because it designates both
-  //   a direct non-virtual base class and an inherited virtual base
-  //   class, the mem-initializer is ill-formed.
-  if (DirectBaseSpec && VirtualBaseSpec)
-    return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
-      << MemberOrBase << SourceRange(IdLoc, RParenLoc);
-  // C++ [base.class.init]p2:
-  // Unless the mem-initializer-id names a nonstatic data membeer of the
-  // constructor's class ot a direst or virtual base of that class, the
-  // mem-initializer is ill-formed.
-  if (!DirectBaseSpec && !VirtualBaseSpec)
-    return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
-    << BaseType << ClassDecl->getNameAsCString()
-    << SourceRange(IdLoc, RParenLoc);
-  DeclarationName Name 
-    = Context.DeclarationNames.getCXXConstructorName(
-        Context.getCanonicalType(BaseType));
   CXXConstructorDecl *C = 0;
-  if (!BaseType->isDependentType())
-    C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs, IdLoc, 
-                                       SourceRange(IdLoc, RParenLoc), Name,
-                                       IK_Direct);
-  
-  return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
+  if (!BaseType->isDependentType() && !HasDependentArg) {
+    DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
+                                            Context.getCanonicalType(BaseType));
+    C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs,
+                                           IdLoc, SourceRange(IdLoc, RParenLoc), 
+                                           Name, IK_Direct);
+  }
+
+  return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args, 
                                                   NumArgs, C, IdLoc);
 }
 
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h	(revision 77084)
+++ lib/Sema/Sema.h	(working copy)
@@ -1922,6 +1922,15 @@
                                             SourceLocation *CommaLocs,
                                             SourceLocation RParenLoc);
 
+  MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+                                       unsigned NumArgs, SourceLocation IdLoc,
+                                       SourceLocation RParenLoc);
+
+  MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args,
+                                     unsigned NumArgs, SourceLocation IdLoc,
+                                     SourceLocation RParenLoc,
+                                     CXXRecordDecl *ClassDecl);
+
   void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
 
   virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, 
-------------- next part --------------
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp	(revision 77084)
+++ lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -716,19 +716,46 @@
 
     // FIXME: Handle members of an anonymous union.
 
-    if (Member) {
+    if (Member)
+      return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
+                                    RParenLoc);
+  }
+  // It didn't name a member, so see if it names a class.
+  TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy 
+                     : getTypeName(*MemberOrBase, IdLoc, S, &SS);
+  if (!BaseTy)
+    return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
+      << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+  
+  QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
+
+  return BuildBaseInitializer(BaseType, (Expr **)Args, NumArgs, IdLoc,
+                              RParenLoc, ClassDecl);
+}
+
+Sema::MemInitResult
+Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+                             unsigned NumArgs, SourceLocation IdLoc,
+                             SourceLocation RParenLoc) {
+  bool HasDependentArg = false;
+  for (unsigned i = 0; i < NumArgs; i++)
+    HasDependentArg |= Args[i]->isTypeDependent();
+
       CXXConstructorDecl *C = 0;
       QualType FieldType = Member->getType();
       if (const ArrayType *Array = Context.getAsArrayType(FieldType))
         FieldType = Array->getElementType();
-      if (!FieldType->isDependentType() && FieldType->getAsRecordType())
+  if (FieldType->isDependentType()) {
+    // Can't check init for dependent type.
+  } else if (FieldType->getAsRecordType()) {
+    if (!HasDependentArg)
         C = PerformInitializationByConstructor(
               FieldType, (Expr **)Args, NumArgs, IdLoc, 
               SourceRange(IdLoc, RParenLoc), Member->getDeclName(), IK_Direct);
-      else if (NumArgs != 1)
+  } else if (NumArgs != 1) {
         return Diag(IdLoc, diag::err_mem_initializer_mismatch) 
-                    << MemberOrBase << SourceRange(IdLoc, RParenLoc);
-      else {
+                << Member->getDeclName() << SourceRange(IdLoc, RParenLoc);
+  } else if (!HasDependentArg) {
         Expr * NewExp = (Expr*)Args[0];
         if (PerformCopyInitialization(NewExp, FieldType, "passing"))
           return true;
@@ -738,16 +765,17 @@
       return new (Context) CXXBaseOrMemberInitializer(Member, (Expr **)Args, 
                                                       NumArgs, C, IdLoc);
     }
-  }
-  // It didn't name a member, so see if it names a class.
-  TypeTy *BaseTy = TemplateTypeTy ? TemplateTypeTy 
-                     : getTypeName(*MemberOrBase, IdLoc, S, &SS);
-  if (!BaseTy)
-    return Diag(IdLoc, diag::err_mem_init_not_member_or_class)
-      << MemberOrBase << SourceRange(IdLoc, RParenLoc);
   
-  QualType BaseType = QualType::getFromOpaquePtr(BaseTy);
-  if (!BaseType->isRecordType() && !BaseType->isDependentType())
+Sema::MemInitResult
+Sema::BuildBaseInitializer(QualType BaseType, Expr **Args,
+                           unsigned NumArgs, SourceLocation IdLoc,
+                           SourceLocation RParenLoc, CXXRecordDecl *ClassDecl) {
+  bool HasDependentArg = false;
+  for (unsigned i = 0; i < NumArgs; i++)
+    HasDependentArg |= Args[i]->isTypeDependent();
+
+  if (!BaseType->isDependentType()) {
+    if (!BaseType->isRecordType())
     return Diag(IdLoc, diag::err_base_init_does_not_name_class)
       << BaseType << SourceRange(IdLoc, RParenLoc);
 
@@ -760,8 +788,8 @@
   
   // First, check for a direct base class.
   const CXXBaseSpecifier *DirectBaseSpec = 0;
-  for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
-       Base != ClassDecl->bases_end(); ++Base) {
+    for (CXXRecordDecl::base_class_const_iterator Base =
+         ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) {
     if (Context.getCanonicalType(BaseType).getUnqualifiedType() == 
         Context.getCanonicalType(Base->getType()).getUnqualifiedType()) {
       // We found a direct base of this type. That's what we're
@@ -797,7 +825,7 @@
   //   class, the mem-initializer is ill-formed.
   if (DirectBaseSpec && VirtualBaseSpec)
     return Diag(IdLoc, diag::err_base_init_direct_and_virtual)
-      << MemberOrBase << SourceRange(IdLoc, RParenLoc);
+        << BaseType << SourceRange(IdLoc, RParenLoc);
   // C++ [base.class.init]p2:
   // Unless the mem-initializer-id names a nonstatic data membeer of the
   // constructor's class ot a direst or virtual base of that class, the
@@ -806,14 +834,16 @@
     return Diag(IdLoc, diag::err_not_direct_base_or_virtual)
     << BaseType << ClassDecl->getNameAsCString()
     << SourceRange(IdLoc, RParenLoc);
-  DeclarationName Name 
-    = Context.DeclarationNames.getCXXConstructorName(
+  }
+
+  CXXConstructorDecl *C = 0;
+  if (!BaseType->isDependentType() && !HasDependentArg) {
+    DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
         Context.getCanonicalType(BaseType));
-  CXXConstructorDecl *C = 0;
-  if (!BaseType->isDependentType())
-    C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs, IdLoc, 
-                                       SourceRange(IdLoc, RParenLoc), Name,
-                                       IK_Direct);
+    C = PerformInitializationByConstructor(BaseType, (Expr **)Args, NumArgs,
+                                           IdLoc, SourceRange(IdLoc, RParenLoc), 
+                                           Name, IK_Direct);
+  }
   
   return new (Context) CXXBaseOrMemberInitializer(BaseType, (Expr **)Args,
                                                   NumArgs, C, IdLoc);
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h	(revision 77084)
+++ lib/Sema/Sema.h	(working copy)
@@ -1922,6 +1922,15 @@
                                             SourceLocation *CommaLocs,
                                             SourceLocation RParenLoc);
 
+  MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args,
+                                       unsigned NumArgs, SourceLocation IdLoc,
+                                       SourceLocation RParenLoc);
+
+  MemInitResult BuildBaseInitializer(QualType BaseType, Expr **Args,
+                                     unsigned NumArgs, SourceLocation IdLoc,
+                                     SourceLocation RParenLoc,
+                                     CXXRecordDecl *ClassDecl);
+
   void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl);
 
   virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, 


More information about the cfe-commits mailing list