]> granicus.if.org Git - clang/commitdiff
Eliminate Sema::CheckValueInitialization; its callers now use
authorDouglas Gregor <dgregor@apple.com>
Wed, 16 Dec 2009 06:35:08 +0000 (06:35 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 16 Dec 2009 06:35:08 +0000 (06:35 +0000)
InitializationSequence to perform the actual initialization.

Also, introduced the notion of a tree of initialized entities, so that
we can know where an initialization began when dealing with nested
initializations (as occur when performing list initialization). This
will, eventually, be useful for producing better diagnostics when list
initialization fails, because we can show the path from the top-level
object being initialized down to the actual subobject where
initialization failed.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91516 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaInit.cpp
lib/Sema/SemaInit.h

index c489b1ea41840680f5dc3e86d45adb56823cc742..28a6bba7f4601d3c2f3d20d2420f13bbc17d6541 100644 (file)
@@ -3693,11 +3693,10 @@ public:
   bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
                              const InitializedEntity &Entity,
                              const InitializationKind &Kind);
-  bool CheckInitList(InitListExpr *&InitList, QualType &DeclType);
+  bool CheckInitList(const InitializedEntity &Entity,
+                     InitListExpr *&InitList, QualType &DeclType);
   bool CheckForConstantInitializer(Expr *e, QualType t);
 
-  bool CheckValueInitialization(QualType Type, SourceLocation Loc);
-
   // type checking C++ declaration initializers (C++ [dcl.init]).
 
   /// ReferenceCompareResult - Expresses the result of comparing two
index 28e11a1010fb8f2ce1e4bc45920ec86535ed97e7..04506908f07b91ebde7a2a8da35f885817182964 100644 (file)
@@ -299,7 +299,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
     return CheckSingleInitializer(Init, DeclType, DirectInit, *this);
   }
 
-  bool hadError = CheckInitList(InitList, DeclType);
+  bool hadError = CheckInitList(Entity, InitList, DeclType);
   Init = InitList;
   return hadError;
 }
@@ -403,9 +403,11 @@ class InitListChecker {
   int numArrayElements(QualType DeclType);
   int numStructUnionElements(QualType DeclType);
 
-  void FillInValueInitializations(InitListExpr *ILE);
+  void FillInValueInitializations(const InitializedEntity &Entity,
+                                  InitListExpr *ILE, bool &RequiresSecondPass);
 public:
-  InitListChecker(Sema &S, InitListExpr *IL, QualType &T);
+  InitListChecker(Sema &S, const InitializedEntity &Entity,
+                  InitListExpr *IL, QualType &T);
   bool HadError() { return hadError; }
 
   // @brief Retrieves the fully-structured initializer list used for
@@ -417,7 +419,10 @@ public:
 /// Recursively replaces NULL values within the given initializer list
 /// with expressions that perform value-initialization of the
 /// appropriate type.
-void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
+void 
+InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
+                                            InitListExpr *ILE,
+                                            bool &RequiresSecondPass) {
   assert((ILE->getType() != SemaRef.Context.VoidTy) &&
          "Should not have void type");
   SourceLocation Loc = ILE->getSourceRange().getBegin();
@@ -433,7 +438,12 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
       if (Field->isUnnamedBitfield())
         continue;
 
+      InitializedEntity MemberEntity 
+        = InitializedEntity::InitializeMember(*Field, &Entity);
       if (Init >= NumInits || !ILE->getInit(Init)) {
+        // FIXME: We probably don't need to handle references
+        // specially here, since value-initialization of references is
+        // handled in InitializationSequence.
         if (Field->getType()->isReferenceType()) {
           // C++ [dcl.init.aggr]p9:
           //   If an incomplete or empty initializer-list leaves a
@@ -446,20 +456,42 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
                         diag::note_uninit_reference_member);
           hadError = true;
           return;
-        } else if (SemaRef.CheckValueInitialization(Field->getType(), Loc)) {
+        } 
+          
+        InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
+                                                                  true);
+        InitializationSequence InitSeq(SemaRef, MemberEntity, Kind, 0, 0);
+        if (!InitSeq) {
+          InitSeq.Diagnose(SemaRef, MemberEntity, Kind, 0, 0);
           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(Field->getType()));
+        Sema::OwningExprResult MemberInit
+          = InitSeq.Perform(SemaRef, MemberEntity, Kind, 
+                            Sema::MultiExprArg(SemaRef, 0, 0));
+        if (MemberInit.isInvalid()) {
+          hadError = 0;
+          return;
+        }
+
+        if (hadError) {
+          // Do nothing
+        } else if (Init < NumInits) {
+          ILE->setInit(Init, MemberInit.takeAs<Expr>());
+        } else if (InitSeq.getKind()
+                         == InitializationSequence::ConstructorInitialization) {
+          // Value-initialization requires a constructor call, so
+          // extend the initializer list to include the constructor
+          // call and make a note that we'll need to take another pass
+          // through the initializer list.
+          ILE->updateInit(Init, MemberInit.takeAs<Expr>());
+          RequiresSecondPass = true;
+        }
       } else if (InitListExpr *InnerILE
                  = dyn_cast<InitListExpr>(ILE->getInit(Init)))
-        FillInValueInitializations(InnerILE);
+          FillInValueInitializations(MemberEntity, InnerILE, 
+                                     RequiresSecondPass);
       ++Init;
 
       // Only look at the first initialization of a union.
@@ -472,39 +504,68 @@ void InitListChecker::FillInValueInitializations(InitListExpr *ILE) {
 
   QualType ElementType;
 
+  InitializedEntity ElementEntity = Entity;
   unsigned NumInits = ILE->getNumInits();
   unsigned NumElements = NumInits;
   if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) {
     ElementType = AType->getElementType();
     if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType))
       NumElements = CAType->getSize().getZExtValue();
+    ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 
+                                                         0, Entity);
   } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) {
     ElementType = VType->getElementType();
     NumElements = VType->getNumElements();
+    ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 
+                                                         0, Entity);
   } else
     ElementType = ILE->getType();
 
+  
   for (unsigned Init = 0; Init != NumElements; ++Init) {
+    if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement)
+      ElementEntity.setElementIndex(Init);
+
     if (Init >= NumInits || !ILE->getInit(Init)) {
-      if (SemaRef.CheckValueInitialization(ElementType, Loc)) {
+      InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
+                                                                true);
+      InitializationSequence InitSeq(SemaRef, ElementEntity, Kind, 0, 0);
+      if (!InitSeq) {
+        InitSeq.Diagnose(SemaRef, ElementEntity, Kind, 0, 0);
         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));
+      Sema::OwningExprResult ElementInit
+        = InitSeq.Perform(SemaRef, ElementEntity, Kind, 
+                          Sema::MultiExprArg(SemaRef, 0, 0));
+      if (ElementInit.isInvalid()) {
+        hadError = 0;
+        return;
+      }
+
+      if (hadError) {
+        // Do nothing
+      } else if (Init < NumInits) {
+        ILE->setInit(Init, ElementInit.takeAs<Expr>());
+      } else if (InitSeq.getKind()
+                   == InitializationSequence::ConstructorInitialization) {
+        // Value-initialization requires a constructor call, so
+        // extend the initializer list to include the constructor
+        // call and make a note that we'll need to take another pass
+        // through the initializer list.
+        ILE->updateInit(Init, ElementInit.takeAs<Expr>());
+        RequiresSecondPass = true;
+      }
     } else if (InitListExpr *InnerILE
-               = dyn_cast<InitListExpr>(ILE->getInit(Init)))
-      FillInValueInitializations(InnerILE);
+                 = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+      FillInValueInitializations(ElementEntity, InnerILE, RequiresSecondPass);
   }
 }
 
 
-InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T)
+InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
+                                 InitListExpr *IL, QualType &T)
   : SemaRef(S) {
   hadError = false;
 
@@ -515,8 +576,13 @@ InitListChecker::InitListChecker(Sema &S, InitListExpr *IL, QualType &T)
   CheckExplicitInitList(IL, T, newIndex, FullyStructuredList, newStructuredIndex,
                         /*TopLevelObject=*/true);
 
-  if (!hadError)
-    FillInValueInitializations(FullyStructuredList);
+  if (!hadError) {
+    bool RequiresSecondPass = false;
+    FillInValueInitializations(Entity, FullyStructuredList, RequiresSecondPass);
+    if (RequiresSecondPass)
+      FillInValueInitializations(Entity, FullyStructuredList, 
+                                 RequiresSecondPass);
+  }
 }
 
 int InitListChecker::numArrayElements(QualType DeclType) {
@@ -1848,84 +1914,42 @@ Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
   return Owned(DIE);
 }
 
-bool Sema::CheckInitList(InitListExpr *&InitList, QualType &DeclType) {
-  InitListChecker CheckInitList(*this, InitList, DeclType);
+bool Sema::CheckInitList(const InitializedEntity &Entity,
+                         InitListExpr *&InitList, QualType &DeclType) {
+  InitListChecker CheckInitList(*this, Entity, InitList, DeclType);
   if (!CheckInitList.HadError())
     InitList = CheckInitList.getFullyStructuredList();
 
   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->getAs<RecordType>()) {
-    if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
-      // -- 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 (ClassDecl->hasUserDeclaredConstructor()) {
-        ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this);
+//===----------------------------------------------------------------------===//
+// Initialization entity
+//===----------------------------------------------------------------------===//
 
-        // FIXME: Poor location information
-        CXXConstructorDecl *Constructor
-          = PerformInitializationByConstructor(Type, 
-                                               MultiExprArg(*this, 0, 0),
-                                               Loc, SourceRange(Loc),
-                                               DeclarationName(),
-                                 InitializationKind::CreateValue(Loc, Loc, Loc),
-                                               ConstructorArgs);
-        if (!Constructor)
-          return true;
-        
-        OwningExprResult Init
-          = BuildCXXConstructExpr(Loc, Type, Constructor,
-                                  move_arg(ConstructorArgs));
-        if (Init.isInvalid())
-          return true;
-        
-        // FIXME: Actually perform the value-initialization!
-        return false;
-      }
-    }
+InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, 
+                                     const InitializedEntity &Parent)
+  : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index) 
+{
+  if (isa<ArrayType>(Parent.TL.getType())) {
+    TL = cast<ArrayTypeLoc>(Parent.TL).getElementLoc();
+    return;
   }
 
-  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. [...]
-    // FIXME: Once we have code that goes through this path, add an actual
-    // diagnostic :)
-  }
+  // FIXME: should be able to get type location information for vectors, too.
 
-  return false;
-}
+  QualType T;
+  if (const ArrayType *AT = Context.getAsArrayType(Parent.TL.getType()))
+    T = AT->getElementType();
+  else
+    T = Parent.TL.getType()->getAs<VectorType>()->getElementType();
 
-//===----------------------------------------------------------------------===//
-// Initialization entity
-//===----------------------------------------------------------------------===//
+  // FIXME: Once we've gone through the effort to create the fake 
+  // TypeSourceInfo, should we cache it somewhere? (If not, we "leak" it).
+  TypeSourceInfo *DI = Context.CreateTypeSourceInfo(T);
+  DI->getTypeLoc().initialize(Parent.TL.getSourceRange().getBegin());
+  TL = DI->getTypeLoc();
+}
 
 void InitializedEntity::InitDeclLoc() {
   assert((Kind == EK_Variable || Kind == EK_Parameter || Kind == EK_Member) &&
@@ -1969,6 +1993,7 @@ DeclarationName InitializedEntity::getName() const {
   case EK_Exception:
   case EK_Temporary:
   case EK_Base:
+  case EK_ArrayOrVectorElement:
     return DeclarationName();
   }
   
@@ -3161,7 +3186,7 @@ InitializationSequence::Perform(Sema &S,
     case SK_ListInitialization: {
       InitListExpr *InitList = cast<InitListExpr>(CurInitExpr);
       QualType Ty = Step->Type;
-      if (S.CheckInitList(InitList, ResultType? *ResultType : Ty))
+      if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty))
         return S.ExprError();
 
       CurInit.release();
@@ -3193,7 +3218,9 @@ InitializationSequence::Perform(Sema &S,
     }
         
     case SK_ZeroInitialization: {
-      if (Kind.getKind() == InitializationKind::IK_Value)
+      if (Kind.getKind() == InitializationKind::IK_Value &&
+          S.getLangOptions().CPlusPlus &&
+          !Kind.isImplicitValueInit())
         CurInit = S.Owned(new (S.Context) CXXZeroInitValueExpr(Step->Type,
                                                    Kind.getRange().getBegin(),
                                                     Kind.getRange().getEnd()));
index c084025b817b6ef5616e36ba8d9bf40172434e61..da6587bcca8dda96dcd7c3258ff46f7d0ea97958 100644 (file)
@@ -53,13 +53,20 @@ public:
     EK_Base,
     /// \brief The entity being initialized is a non-static data member 
     /// subobject.
-    EK_Member
+    EK_Member,
+    /// \brief The entity being initialized is an element of an array
+    /// or vector.
+    EK_ArrayOrVectorElement
   };
   
 private:
   /// \brief The kind of entity being initialized.
   EntityKind Kind;
 
+  /// \brief If non-NULL, the parent entity in which this
+  /// initialization occurs.
+  const InitializedEntity *Parent;
+
   /// \brief The type of the object or reference being initialized along with 
   /// its location information.
   TypeLoc TL;
@@ -77,13 +84,17 @@ private:
     /// \brief When Kind == EK_Base, the base specifier that provides the 
     /// base class.
     CXXBaseSpecifier *Base;
+
+    /// \brief When Kind = EK_ArrayOrVectorElement, the index of the
+    /// array or vector element being initialized.
+    unsigned Index;
   };
 
   InitializedEntity() { }
 
   /// \brief Create the initialization entity for a variable.
   InitializedEntity(VarDecl *Var)
-    : Kind(EK_Variable), 
+    : Kind(EK_Variable), Parent(0),
       VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Var)) 
   {
     InitDeclLoc();
@@ -91,7 +102,7 @@ private:
   
   /// \brief Create the initialization entity for a parameter.
   InitializedEntity(ParmVarDecl *Parm)
-    : Kind(EK_Parameter), 
+    : Kind(EK_Parameter), Parent(0),
       VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Parm)) 
   { 
     InitDeclLoc();
@@ -100,16 +111,20 @@ private:
   /// \brief Create the initialization entity for the result of a function,
   /// throwing an object, or performing an explicit cast.
   InitializedEntity(EntityKind Kind, SourceLocation Loc, TypeLoc TL)
-    : Kind(Kind), TL(TL), Location(Loc.getRawEncoding()) { }
+    : Kind(Kind), Parent(0), TL(TL), Location(Loc.getRawEncoding()) { }
   
   /// \brief Create the initialization entity for a member subobject.
-  InitializedEntity(FieldDecl *Member) 
-    : Kind(EK_Member), 
+  InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent
+    : Kind(EK_Member), Parent(Parent),
       VariableOrMember(reinterpret_cast<DeclaratorDecl*>(Member))
   { 
     InitDeclLoc();
   }
   
+  /// \brief Create the initialization entity for an array element.
+  InitializedEntity(ASTContext &Context, unsigned Index, 
+                    const InitializedEntity &Parent);
+
   /// \brief Initialize type-location information from a declaration.
   void InitDeclLoc();
   
@@ -145,14 +160,27 @@ public:
   static InitializedEntity InitializeBase(ASTContext &Context,
                                           CXXBaseSpecifier *Base);
   
-  /// \brief Create the initialize entity for a member subobject.
-  static InitializedEntity InitializeMember(FieldDecl *Member) {
-    return InitializedEntity(Member);
+  /// \brief Create the initialization entity for a member subobject.
+  static InitializedEntity InitializeMember(FieldDecl *Member,
+                                          const InitializedEntity *Parent = 0) {
+    return InitializedEntity(Member, Parent);
   }
   
+  /// \brief Create the initialization entity for an array element.
+  static InitializedEntity InitializeElement(ASTContext &Context, 
+                                             unsigned Index, 
+                                             const InitializedEntity &Parent) {
+    return InitializedEntity(Context, Index, Parent);
+  }
+
   /// \brief Determine the kind of initialization.
   EntityKind getKind() const { return Kind; }
   
+  /// \brief Retrieve the parent of the entity being initialized, when
+  /// the initialization itself is occuring within the context of a
+  /// larger initialization.
+  const InitializedEntity *getParent() const { return Parent; }
+
   /// \brief Retrieve type being initialized.
   TypeLoc getType() const { return TL; }
   
@@ -172,6 +200,13 @@ public:
     assert(getKind() == EK_Exception && "No 'throw' location!");
     return SourceLocation::getFromRawEncoding(Location);
   }
+
+  /// \brief If this is already the initializer for an array or vector
+  /// element, sets the element index.
+  void setElementIndex(unsigned Index) {
+    assert(getKind() == EK_ArrayOrVectorElement);
+    this->Index = Index;
+  }
 };
   
 /// \brief Describes the kind of initialization being performed, along with 
@@ -194,6 +229,7 @@ private:
     SIK_Copy = IK_Copy,       ///< Copy initialization
     SIK_Default = IK_Default, ///< Default initialization
     SIK_Value = IK_Value,     ///< Value initialization
+    SIK_ImplicitValue,        ///< Implicit value initialization
     SIK_DirectCast,  ///< Direct initialization due to a cast
     /// \brief Direct initialization due to a C-style or functional cast.
     SIK_DirectCStyleOrFunctionalCast
@@ -245,15 +281,19 @@ public:
   /// \brief Create a value initialization.
   static InitializationKind CreateValue(SourceLocation InitLoc,
                                         SourceLocation LParenLoc,
-                                        SourceLocation RParenLoc) {
-    return InitializationKind(SIK_Value, InitLoc, LParenLoc, RParenLoc);
+                                        SourceLocation RParenLoc,
+                                        bool isImplicit = false) {
+    return InitializationKind(isImplicit? SIK_ImplicitValue : SIK_Value, 
+                              InitLoc, LParenLoc, RParenLoc);
   }
   
   /// \brief Determine the initialization kind.
   InitKind getKind() const {
-    if (Kind > SIK_Value)
+    if (Kind > SIK_ImplicitValue)
       return IK_Direct;
-    
+    if (Kind == SIK_ImplicitValue)
+      return IK_Value;
+
     return (InitKind)Kind;
   }
   
@@ -266,7 +306,12 @@ public:
   bool isCStyleOrFunctionalCast() const { 
     return Kind == SIK_DirectCStyleOrFunctionalCast; 
   }
-  
+
+  /// \brief Determine whether this initialization is an implicit
+  /// value-initialization, e.g., as occurs during aggregate
+  /// initialization.
+  bool isImplicitValueInit() const { return Kind == SIK_ImplicitValue; }
+
   /// \brief Retrieve the location at which initialization is occurring.
   SourceLocation getLocation() const { return Locations[0]; }