[cfe-commits] r63525 - in /cfe/trunk: include/clang/AST/Expr.h lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaInit.cpp test/SemaCXX/dcl_init_aggr.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 2 09:43:22 PST 2009


Author: dgregor
Date: Mon Feb  2 11:43:21 2009
New Revision: 63525

URL: http://llvm.org/viewvc/llvm-project?rev=63525&view=rev
Log:
Check value-initializations that occur when an initializer list
provides too few elements.


Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=63525&r1=63524&r2=63525&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Mon Feb  2 11:43:21 2009
@@ -1725,6 +1725,8 @@
     return LBraceLoc.isValid() && RBraceLoc.isValid();
   }
   
+  void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; }
+
   /// @brief Retrieve the initializer list that describes the
   /// syntactic form of the initializer.
   ///

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=63525&r1=63524&r2=63525&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb  2 11:43:21 2009
@@ -1715,6 +1715,7 @@
   
   StringLiteral *IsStringLiteralInit(Expr *Init, QualType DeclType);
   bool CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT);
+  bool CheckValueInitialization(QualType Type, SourceLocation Loc);
 
   // type checking C++ declaration initializers (C++ [dcl.init]).
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=63525&r1=63524&r2=63525&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Feb  2 11:43:21 2009
@@ -1592,13 +1592,20 @@
     return cast<CXXConstructorDecl>(Best->Function);
     
   case OR_No_Viable_Function:
-    Diag(Loc, diag::err_ovl_no_viable_function_in_init)
-      << InitEntity << (unsigned)CandidateSet.size() << Range;
+    if (InitEntity)
+      Diag(Loc, diag::err_ovl_no_viable_function_in_init)
+        << InitEntity << (unsigned)CandidateSet.size() << Range;
+    else
+      Diag(Loc, diag::err_ovl_no_viable_function_in_init)
+        << ClassType << (unsigned)CandidateSet.size() << Range;
     PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
     return 0;
     
   case OR_Ambiguous:
-    Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
+    if (InitEntity)
+      Diag(Loc, diag::err_ovl_ambiguous_init) << InitEntity << Range;
+    else
+      Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
     PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
     return 0;
   }

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=63525&r1=63524&r2=63525&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Feb  2 11:43:21 2009
@@ -127,6 +127,10 @@
 void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
   assert((ILE->getType() != SemaRef->Context.VoidTy) && 
          "Should not have void type");
+  SourceLocation Loc = ILE->getSourceRange().getBegin();
+  if (ILE->getSyntacticForm())
+    Loc = ILE->getSyntacticForm()->getSourceRange().getBegin();
+  
   if (const RecordType *RType = ILE->getType()->getAsRecordType()) {
     unsigned Init = 0, NumInits = ILE->getNumInits();
     for (RecordDecl::field_iterator Field = RType->getDecl()->field_begin(),
@@ -135,24 +139,32 @@
       if (Field->isUnnamedBitfield())
         continue;
 
-      if (Init >= NumInits) {
+      if (Init >= NumInits || !ILE->getInit(Init)) {
         if (Field->getType()->isReferenceType()) {
           // C++ [dcl.init.aggr]p9:
           //   If an incomplete or empty initializer-list leaves a
           //   member of reference type uninitialized, the program is
           //   ill-formed. 
-          SemaRef->Diag(ILE->getSyntacticForm()->getLocStart(), 
-                        diag::err_init_reference_member_uninitialized)
+          SemaRef->Diag(Loc, diag::err_init_reference_member_uninitialized)
             << Field->getType()
             << ILE->getSyntacticForm()->getSourceRange();
           SemaRef->Diag(Field->getLocation(), 
                         diag::note_uninit_reference_member);
           hadError = true;
+          return;
+        } else if (SemaRef->CheckValueInitialization(Field->getType(), Loc)) {
+          hadError = true;
+          return;
         }
-      } else if (!ILE->getInit(Init))
-        ILE->setInit(Init, 
-                new (SemaRef->Context) ImplicitValueInitExpr(Field->getType()));
-      else if (InitListExpr *InnerILE 
+
+        // FIXME: If value-initialization involves calling a
+        // constructor, should we make that call explicit in the
+        // representation (even when it means extending the
+        // initializer list)?
+        if (Init < NumInits && !hadError)
+          ILE->setInit(Init, 
+              new (SemaRef->Context) ImplicitValueInitExpr(Field->getType()));
+      } else if (InitListExpr *InnerILE 
                  = dyn_cast<InitListExpr>(ILE->getInit(Init)))
         FillInValueInitializations(InnerILE);
       ++Init;
@@ -167,18 +179,33 @@
 
   QualType ElementType;
   
-  if (const ArrayType *AType = SemaRef->Context.getAsArrayType(ILE->getType()))
+  unsigned NumInits = ILE->getNumInits();
+  unsigned NumElements = NumInits;
+  if (const ArrayType *AType = SemaRef->Context.getAsArrayType(ILE->getType())) {
     ElementType = AType->getElementType();
-  else if (const VectorType *VType = ILE->getType()->getAsVectorType())
+    if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType))
+      NumElements = CAType->getSize().getZExtValue();
+  } else if (const VectorType *VType = ILE->getType()->getAsVectorType()) {
     ElementType = VType->getElementType();
-  else 
+    NumElements = VType->getNumElements();
+  } else 
     ElementType = ILE->getType();
   
-  for (unsigned Init = 0, NumInits = ILE->getNumInits(); Init != NumInits; 
-       ++Init) {
-    if (!ILE->getInit(Init))
-      ILE->setInit(Init, 
-                   new (SemaRef->Context) ImplicitValueInitExpr(ElementType));
+  for (unsigned Init = 0; Init != NumElements; ++Init) {
+    if (Init >= NumInits || !ILE->getInit(Init)) {
+      if (SemaRef->CheckValueInitialization(ElementType, Loc)) {
+        hadError = true;
+        return;
+      }
+
+      // FIXME: If value-initialization involves calling a
+      // constructor, should we make that call explicit in the
+      // representation (even when it means extending the
+      // initializer list)?
+      if (Init < NumInits && !hadError)
+        ILE->setInit(Init, 
+                     new (SemaRef->Context) ImplicitValueInitExpr(ElementType));
+    }
     else if (InitListExpr *InnerILE =dyn_cast<InitListExpr>(ILE->getInit(Init)))
       FillInValueInitializations(InnerILE);
   }
@@ -254,9 +281,19 @@
   unsigned StructuredSubobjectInitIndex = 0;
 
   // Check the element types and build the structural subobject.
+  unsigned StartIndex = Index;
   CheckListElementTypes(ParentIList, T, false, Index,
                         StructuredSubobjectInitList, 
                         StructuredSubobjectInitIndex);
+  unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
+  
+  // Update the structured sub-object initialize so that it's ending
+  // range corresponds with the end of the last initializer it used.
+  if (EndIndex < ParentIList->getNumInits()) {
+    SourceLocation EndLoc 
+      = ParentIList->getInit(EndIndex)->getSourceRange().getEnd();
+    StructuredSubobjectInitList->setRBraceLoc(EndLoc);
+  }
 }
 
 void InitListChecker::CheckExplicitInitList(InitListExpr *IList, QualType &T,
@@ -1102,9 +1139,12 @@
       << ExistingInit->getSourceRange();
   }
 
+  SourceLocation StartLoc;
+  if (Index < IList->getNumInits())
+    StartLoc = IList->getInit(Index)->getSourceRange().getBegin();
   InitListExpr *Result 
-    = new (SemaRef->Context) InitListExpr(SourceLocation(), 0, 0, 
-                                          SourceLocation());
+    = new (SemaRef->Context) InitListExpr(StartLoc, 0, 0, 
+                                          IList->getSourceRange().getEnd());
   Result->setType(CurrentObjectType);
 
   // Link this new initializer list into the structured initializer
@@ -1257,3 +1297,52 @@
 
   return CheckInitList.HadError();
 }
+
+/// \brief Diagnose any semantic errors with value-initialization of
+/// the given type.
+///
+/// Value-initialization effectively zero-initializes any types
+/// without user-declared constructors, and calls the default
+/// constructor for a for any type that has a user-declared
+/// constructor (C++ [dcl.init]p5). Value-initialization can fail when
+/// a type with a user-declared constructor does not have an
+/// accessible, non-deleted default constructor. In C, everything can
+/// be value-initialized, which corresponds to C's notion of
+/// initializing objects with static storage duration when no
+/// initializer is provided for that object. 
+///
+/// \returns true if there was an error, false otherwise.
+bool Sema::CheckValueInitialization(QualType Type, SourceLocation Loc) {
+  // C++ [dcl.init]p5:
+  //
+  //   To value-initialize an object of type T means:
+
+  //     -- if T is an array type, then each element is value-initialized;
+  if (const ArrayType *AT = Context.getAsArrayType(Type))
+    return CheckValueInitialization(AT->getElementType(), Loc);
+
+  if (const RecordType *RT = Type->getAsRecordType()) {
+    if (const CXXRecordType *CXXRec = dyn_cast<CXXRecordType>(RT)) {
+      // -- if T is a class type (clause 9) with a user-declared
+      //    constructor (12.1), then the default constructor for T is
+      //    called (and the initialization is ill-formed if T has no
+      //    accessible default constructor);
+      if (CXXRec->getDecl()->hasUserDeclaredConstructor())
+        // FIXME: Eventually, we'll need to put the constructor decl
+        // into the AST.
+        return PerformInitializationByConstructor(Type, 0, 0, Loc,
+                                                  SourceRange(Loc), 
+                                                  DeclarationName(),
+                                                  IK_Direct);
+    }
+  }
+
+  if (Type->isReferenceType()) {
+    // C++ [dcl.init]p5:
+    //   [...] A program that calls for default-initialization or
+    //   value-initialization of an entity of reference type is
+    //   ill-formed. [...]
+  }
+
+  return false;
+}

Modified: cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp?rev=63525&r1=63524&r2=63525&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp (original)
+++ cfe/trunk/test/SemaCXX/dcl_init_aggr.cpp Mon Feb  2 11:43:21 2009
@@ -40,6 +40,21 @@
 struct TooFew { int a; char* b; int c; }; 
 TooFew too_few = { 1, "asdf" }; // okay
 
+struct NoDefaultConstructor { // expected-note{{candidate function}}
+  NoDefaultConstructor(int); // expected-note{{candidate function}}
+};
+struct TooFewError {
+  int a;
+  NoDefaultConstructor nodef;
+};
+TooFewError too_few_okay = { 1, 1 };
+TooFewError too_few_error = { 1 }; // expected-error{{no matching constructor}}
+
+TooFewError too_few_okay2[2] = { 1, 1 };
+TooFewError too_few_error2[2] = { 1 }; // expected-error{{no matching constructor}}
+
+NoDefaultConstructor too_few_error3[3] = { }; // expected-error{{no matching constructor}}
+
 // C++ [dcl.init.aggr]p8
 struct Empty { };
 struct EmptyTest {





More information about the cfe-commits mailing list