Issue diagnostics in variety of situations involving
reference/const data members when user has declared
the constructor. This necessitated some non-minor
refactoring.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80934 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 6a3dfc9..7c854be 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -792,6 +792,11 @@
   } else if (!HasDependentArg) {
     Expr *NewExp;
     if (NumArgs == 0) {
+      if (FieldType->isReferenceType()) {
+        Diag(IdLoc, diag::err_null_intialized_reference_member)
+              << Member->getDeclName();
+        return Diag(Member->getLocation(), diag::note_declared_at);
+      }
       NewExp = new (Context) CXXZeroInitValueExpr(FieldType, IdLoc, RParenLoc);
       NumArgs = 1;
     }
@@ -890,6 +895,175 @@
 }
 
 void
+Sema::setBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
+                              CXXBaseOrMemberInitializer **Initializers,
+                              unsigned NumInitializers,
+                              llvm::SmallVectorImpl<CXXBaseSpecifier *>& Bases,          
+                              llvm::SmallVectorImpl<FieldDecl *>&Fields) {
+  // We need to build the initializer AST according to order of construction
+  // and not what user specified in the Initializers list.
+  CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());
+  llvm::SmallVector<CXXBaseOrMemberInitializer*, 32> AllToInit;
+  llvm::DenseMap<const void *, CXXBaseOrMemberInitializer*> AllBaseFields;
+  bool HasDependentBaseInit = false;
+  
+  for (unsigned i = 0; i < NumInitializers; i++) {
+    CXXBaseOrMemberInitializer *Member = Initializers[i];
+    if (Member->isBaseInitializer()) {
+      if (Member->getBaseClass()->isDependentType())
+        HasDependentBaseInit = true;
+      AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
+    } else {
+      AllBaseFields[Member->getMember()] = Member;
+    }
+  }
+  
+  if (HasDependentBaseInit) {
+    // FIXME. This does not preserve the ordering of the initializers.
+    // Try (with -Wreorder)
+    // template<class X> struct A {};
+    // template<class X> struct B : A<X> { 
+    //   B() : x1(10), A<X>() {} 
+    //   int x1;
+    // };
+    // B<int> x;
+    // On seeing one dependent type, we should essentially exit this routine
+    // while preserving user-declared initializer list. When this routine is
+    // called during instantiatiation process, this routine will rebuild the
+    // oderdered initializer list correctly.
+    
+    // If we have a dependent base initialization, we can't determine the
+    // association between initializers and bases; just dump the known
+    // initializers into the list, and don't try to deal with other bases.
+    for (unsigned i = 0; i < NumInitializers; i++) {
+      CXXBaseOrMemberInitializer *Member = Initializers[i];
+      if (Member->isBaseInitializer())
+        AllToInit.push_back(Member);
+    }
+  } else {
+    // Push virtual bases before others.
+    for (CXXRecordDecl::base_class_iterator VBase =
+         ClassDecl->vbases_begin(),
+         E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+      if (VBase->getType()->isDependentType())
+        continue;
+      if (CXXBaseOrMemberInitializer *Value = 
+          AllBaseFields.lookup(VBase->getType()->getAs<RecordType>()))
+        AllToInit.push_back(Value);
+      else {
+        CXXRecordDecl *VBaseDecl = 
+        cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+        assert(VBaseDecl && "setBaseOrMemberInitializers - VBaseDecl null");
+        if (!VBaseDecl->getDefaultConstructor(Context))
+          Bases.push_back(VBase);
+        CXXBaseOrMemberInitializer *Member = 
+        new (Context) CXXBaseOrMemberInitializer(VBase->getType(), 0, 0,
+                                    VBaseDecl->getDefaultConstructor(Context),
+                                    SourceLocation(),
+                                    SourceLocation());
+        AllToInit.push_back(Member);
+      }
+    }
+    
+    for (CXXRecordDecl::base_class_iterator Base =
+         ClassDecl->bases_begin(),
+         E = ClassDecl->bases_end(); Base != E; ++Base) {
+      // Virtuals are in the virtual base list and already constructed.
+      if (Base->isVirtual())
+        continue;
+      // Skip dependent types.
+      if (Base->getType()->isDependentType())
+        continue;
+      if (CXXBaseOrMemberInitializer *Value = 
+          AllBaseFields.lookup(Base->getType()->getAs<RecordType>()))
+        AllToInit.push_back(Value);
+      else {
+        CXXRecordDecl *BaseDecl = 
+        cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+        assert(BaseDecl && "setBaseOrMemberInitializers - BaseDecl null");
+        if (!BaseDecl->getDefaultConstructor(Context))
+          Bases.push_back(Base);
+        CXXBaseOrMemberInitializer *Member = 
+        new (Context) CXXBaseOrMemberInitializer(Base->getType(), 0, 0,
+                                      BaseDecl->getDefaultConstructor(Context),
+                                      SourceLocation(),
+                                      SourceLocation());
+        AllToInit.push_back(Member);
+      }
+    }
+  }
+  
+  // non-static data members.
+  for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
+       E = ClassDecl->field_end(); Field != E; ++Field) {
+    if ((*Field)->isAnonymousStructOrUnion()) {
+      if (const RecordType *FieldClassType = 
+          Field->getType()->getAs<RecordType>()) {
+        CXXRecordDecl *FieldClassDecl
+        = cast<CXXRecordDecl>(FieldClassType->getDecl());
+        for(RecordDecl::field_iterator FA = FieldClassDecl->field_begin(),
+            EA = FieldClassDecl->field_end(); FA != EA; FA++) {
+          if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*FA)) {
+            // 'Member' is the anonymous union field and 'AnonUnionMember' is
+            // set to the anonymous union data member used in the initializer
+            // list.
+            Value->setMember(*Field);
+            Value->setAnonUnionMember(*FA);
+            AllToInit.push_back(Value);
+            break;
+          }
+        }
+      }
+      continue;
+    }
+    if (CXXBaseOrMemberInitializer *Value = AllBaseFields.lookup(*Field)) {
+      AllToInit.push_back(Value);
+      continue;
+    }
+    
+    QualType FT = Context.getBaseElementType((*Field)->getType());
+    if (const RecordType* RT = FT->getAs<RecordType>()) {
+      CXXConstructorDecl *Ctor =
+        cast<CXXRecordDecl>(RT->getDecl())->getDefaultConstructor(Context);
+      if (!Ctor && !FT->isDependentType())
+        Fields.push_back(*Field);
+      CXXBaseOrMemberInitializer *Member = 
+      new (Context) CXXBaseOrMemberInitializer((*Field), 0, 0,
+                                         Ctor,
+                                         SourceLocation(),
+                                         SourceLocation());
+      AllToInit.push_back(Member);
+      if (FT.isConstQualified() && (!Ctor || Ctor->isTrivial())) {
+        Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+          << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
+        Diag((*Field)->getLocation(), diag::note_declared_at);
+      }
+    }
+    else if (FT->isReferenceType()) {
+      Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+        << Context.getTagDeclType(ClassDecl) << 0 << (*Field)->getDeclName();
+      Diag((*Field)->getLocation(), diag::note_declared_at);
+    }
+    else if (FT.isConstQualified()) {
+      Diag(Constructor->getLocation(), diag::err_unintialized_member_in_ctor)
+        << Context.getTagDeclType(ClassDecl) << 1 << (*Field)->getDeclName();
+      Diag((*Field)->getLocation(), diag::note_declared_at);
+    }
+  }
+  
+  NumInitializers = AllToInit.size();
+  if (NumInitializers > 0) {
+    Constructor->setNumBaseOrMemberInitializers(NumInitializers);
+    CXXBaseOrMemberInitializer **baseOrMemberInitializers =
+      new (Context) CXXBaseOrMemberInitializer*[NumInitializers];
+    
+    Constructor->setBaseOrMemberInitializers(baseOrMemberInitializers);
+    for (unsigned Idx = 0; Idx < NumInitializers; ++Idx)
+      baseOrMemberInitializers[Idx] = AllToInit[Idx];
+  }
+}
+
+void
 Sema::BuildBaseOrMemberInitializers(ASTContext &C,
                                  CXXConstructorDecl *Constructor,
                                  CXXBaseOrMemberInitializer **Initializers,
@@ -898,9 +1072,8 @@
   llvm::SmallVector<CXXBaseSpecifier *, 4>Bases;
   llvm::SmallVector<FieldDecl *, 4>Members;
   
-  Constructor->setBaseOrMemberInitializers(C, 
-                                           Initializers, NumInitializers,
-                                           Bases, Members);
+  setBaseOrMemberInitializers(Constructor, 
+                              Initializers, NumInitializers, Bases, Members);
   for (unsigned int i = 0; i < Bases.size(); i++)
     Diag(Bases[i]->getSourceRange().getBegin(), 
          diag::err_missing_default_constructor) << 0 << Bases[i]->getType();