[cfe-commits] r58756 - in /cfe/trunk: lib/AST/DeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/copy-initialization.cpp test/SemaCXX/direct-initializer.cpp

Douglas Gregor doug.gregor at gmail.com
Wed Nov 5 07:29:39 PST 2008


Author: dgregor
Date: Wed Nov  5 09:29:30 2008
New Revision: 58756

URL: http://llvm.org/viewvc/llvm-project?rev=58756&view=rev
Log:
Implement C++ copy-initialization for declarations. There is now some
duplication in the handling of copy-initialization by constructor,
which occurs both for initialization of a declaration and for
overloading. The initialization code is due for some refactoring.


Added:
    cfe/trunk/test/SemaCXX/copy-initialization.cpp   (with props)
Modified:
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/SemaCXX/direct-initializer.cpp

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58756&r1=58755&r2=58756&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Nov  5 09:29:30 2008
@@ -158,7 +158,7 @@
   //     A default constructor for a class X is a constructor of class
   //     X that can be called without an argument.
   return (getNumParams() == 0) ||
-         (getNumParams() > 0 & getParamDecl(1)->getDefaultArg() != 0);
+         (getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0);
 }
 
 bool 

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov  5 09:29:30 2008
@@ -708,11 +708,20 @@
                                              SourceLocation *CommaLocs,
                                              SourceLocation RParenLoc);
 
+  /// InitializationKind - Represents which kind of C++ initialization
+  /// [dcl.init] a routine is to perform.
+  enum InitializationKind {
+    IK_Direct, ///< Direct initialization
+    IK_Copy,   ///< Copy initialization
+    IK_Default ///< Default initialization
+  };
+
   CXXConstructorDecl *
-  PerformDirectInitForClassType(QualType ClassType,
-                                Expr **Args, unsigned NumArgs,
-                                SourceLocation Loc, SourceRange Range,
-                                std::string InitEntity, bool HasInitializer);
+  PerformInitializationByConstructor(QualType ClassType,
+                                     Expr **Args, unsigned NumArgs,
+                                     SourceLocation Loc, SourceRange Range,
+                                     std::string InitEntity,
+                                     InitializationKind Kind);
 
   /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
   virtual ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
@@ -1146,7 +1155,8 @@
   
   /// type checking declaration initializers (C99 6.7.8)
   friend class InitListChecker;
-  bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType);
+  bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType,
+                             SourceLocation InitLoc, std::string InitEntity);
   bool CheckSingleInitializer(Expr *&simpleInit, QualType declType);
   bool CheckForConstantInitializer(Expr *e, QualType t);
   bool CheckArithmeticConstantExpression(const Expr* e);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Nov  5 09:29:30 2008
@@ -627,7 +627,9 @@
   return 0;
 }
 
-bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) {  
+bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
+                                 SourceLocation InitLoc,
+                                 std::string InitEntity) {
   // C++ [dcl.init.ref]p1:
   //   A variable declared to be a T&, that is “reference to type T”
   //   (8.3.2), shall be initialized by an object, or function, of
@@ -638,7 +640,7 @@
   // C99 6.7.8p3: The type of the entity to be initialized shall be an array
   // of unknown size ("[]") or an object type that is not a variable array type.
   if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType))
-    return Diag(VAT->getSizeExpr()->getLocStart(), 
+    return Diag(InitLoc, 
                 diag::err_variable_object_no_init, 
                 VAT->getSizeExpr()->getSourceRange());
   
@@ -648,6 +650,50 @@
     if (StringLiteral *strLiteral = IsStringLiteralInit(Init, DeclType))
       return CheckStringLiteralInit(strLiteral, DeclType);
 
+    // C++ [dcl.init]p14:
+    //   -- If the destination type is a (possibly cv-qualified) class
+    //      type:
+    if (getLangOptions().CPlusPlus && DeclType->isRecordType()) {
+      QualType DeclTypeC = Context.getCanonicalType(DeclType);
+      QualType InitTypeC = Context.getCanonicalType(Init->getType());
+
+      //   -- If the initialization is direct-initialization, or if it is
+      //      copy-initialization where the cv-unqualified version of the
+      //      source type is the same class as, or a derived class of, the
+      //      class of the destination, constructors are considered.
+      if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) ||
+          IsDerivedFrom(InitTypeC, DeclTypeC)) {
+        CXXConstructorDecl *Constructor 
+          = PerformInitializationByConstructor(DeclType, &Init, 1,
+                                               InitLoc, Init->getSourceRange(),
+                                               InitEntity, IK_Copy);
+        return Constructor == 0;
+      }
+
+      //   -- Otherwise (i.e., for the remaining copy-initialization
+      //      cases), user-defined conversion sequences that can
+      //      convert from the source type to the destination type or
+      //      (when a conversion function is used) to a derived class
+      //      thereof are enumerated as described in 13.3.1.4, and the
+      //      best one is chosen through overload resolution
+      //      (13.3). If the conversion cannot be done or is
+      //      ambiguous, the initialization is ill-formed. The
+      //      function selected is called with the initializer
+      //      expression as its argument; if the function is a
+      //      constructor, the call initializes a temporary of the
+      //      destination type.
+      // FIXME: We're pretending to do copy elision here; return to
+      // this when we have ASTs for such things.
+      if (PerformImplicitConversion(Init, DeclType))
+        return Diag(InitLoc,
+                    diag::err_typecheck_convert_incompatible,
+                    DeclType.getAsString(), InitEntity,
+                    "initializing",
+                    Init->getSourceRange());
+      else
+        return false;
+    }
+
     // C99 6.7.8p16.
     if (DeclType->isArrayType())
       return Diag(Init->getLocStart(),
@@ -1574,7 +1620,8 @@
       Diag(VDecl->getLocation(), diag::err_block_extern_cant_init);
       VDecl->setInvalidDecl();
     } else if (!VDecl->isInvalidDecl()) {
-      if (CheckInitializerTypes(Init, DclT))
+      if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
+                                VDecl->getName()))
         VDecl->setInvalidDecl();
       
       // C++ 3.6.2p2, allow dynamic initialization of static initializers.
@@ -1587,7 +1634,8 @@
     if (VDecl->getStorageClass() == VarDecl::Extern)
       Diag(VDecl->getLocation(), diag::warn_extern_init);
     if (!VDecl->isInvalidDecl())
-      if (CheckInitializerTypes(Init, DclT))
+      if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(),
+                                VDecl->getName()))
         VDecl->setInvalidDecl();
     
     // C++ 3.6.2p2, allow dynamic initialization of static initializers.
@@ -1642,12 +1690,13 @@
       if (const ArrayType *Array = Context.getAsArrayType(Type))
         InitType = Array->getElementType();
       if (InitType->isRecordType()) {
-        CXXConstructorDecl *Constructor
-          = PerformDirectInitForClassType(InitType, 0, 0, Var->getLocation(),
-                                          SourceRange(Var->getLocation(),
-                                                      Var->getLocation()),
-                                          Var->getName(),
-                                          /*HasInitializer=*/false);
+        const CXXConstructorDecl *Constructor
+          = PerformInitializationByConstructor(InitType, 0, 0, 
+                                               Var->getLocation(),
+                                               SourceRange(Var->getLocation(),
+                                                           Var->getLocation()),
+                                               Var->getName(),
+                                               IK_Default);
         if (!Constructor)
           Var->setInvalidDecl();
       }

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Nov  5 09:29:30 2008
@@ -835,7 +835,6 @@
   // Add this constructor to the set of constructors of the current
   // class.
   ClassDecl->addConstructor(Context, ConDecl);
-
   return (DeclTy *)ConDecl;
 }
 
@@ -960,15 +959,23 @@
 
   if (VDecl->getType()->isRecordType()) {
     CXXConstructorDecl *Constructor
-      = PerformDirectInitForClassType(DeclInitType, (Expr **)ExprTys, NumExprs,
-                                      VDecl->getLocation(),
-                                      SourceRange(VDecl->getLocation(),
-                                                  RParenLoc),
-                                      VDecl->getName(),
-                                      /*HasInitializer=*/true);
+      = PerformInitializationByConstructor(DeclInitType, 
+                                           (Expr **)ExprTys, NumExprs,
+                                           VDecl->getLocation(),
+                                           SourceRange(VDecl->getLocation(),
+                                                       RParenLoc),
+                                           VDecl->getName(),
+                                           IK_Direct);
     if (!Constructor) {
       RealDecl->setInvalidDecl();
     }
+
+    // Let clients know that initialization was done with a direct
+    // initializer.
+    VDecl->setCXXDirectInitializer(true);
+
+    // FIXME: Add ExprTys and Constructor to the RealDecl as part of
+    // the initializer.
     return;
   }
 
@@ -987,21 +994,26 @@
   AddInitializerToDecl(Dcl, ExprTys[0]);
 }
 
-/// PerformDirectInitForClassType - Perform direct-initialization (C++
-/// [dcl.init]) for a value of the given class type with the given set
-/// of arguments (@p Args). @p Loc is the location in the source code
-/// where the initializer occurs (e.g., a declaration, member
-/// initializer, functional cast, etc.) while @p Range covers the
-/// whole initialization. @p HasInitializer is true if the initializer
-/// was actually written in the source code. When successful, returns
+/// PerformInitializationByConstructor - Perform initialization by
+/// constructor (C++ [dcl.init]p14), which may occur as part of
+/// direct-initialization or copy-initialization. We are initializing
+/// an object of type @p ClassType with the given arguments @p
+/// Args. @p Loc is the location in the source code where the
+/// initializer occurs (e.g., a declaration, member initializer,
+/// functional cast, etc.) while @p Range covers the whole
+/// initialization. @p InitEntity is the entity being initialized,
+/// which may by the name of a declaration or a type. @p Kind is the
+/// kind of initialization we're performing, which affects whether
+/// explicit constructors will be considered. When successful, returns
 /// the constructor that will be used to perform the initialization;
-/// when the initialization fails, emits a diagnostic and returns null.
+/// when the initialization fails, emits a diagnostic and returns
+/// null.
 CXXConstructorDecl *
-Sema::PerformDirectInitForClassType(QualType ClassType,
-                                    Expr **Args, unsigned NumArgs,
-                                    SourceLocation Loc, SourceRange Range,
-                                    std::string InitEntity,
-                                    bool HasInitializer) {
+Sema::PerformInitializationByConstructor(QualType ClassType,
+                                         Expr **Args, unsigned NumArgs,
+                                         SourceLocation Loc, SourceRange Range,
+                                         std::string InitEntity,
+                                         InitializationKind Kind) {
   const RecordType *ClassRec = ClassType->getAsRecordType();
   assert(ClassRec && "Can only initialize a class type here");
 
@@ -1017,15 +1029,23 @@
   //   with the initializer expression(s) as its argument(s). If no
   //   constructor applies, or the overload resolution is ambiguous,
   //   the initialization is ill-formed.
-  //
-  // FIXME: We don't check cv-qualifiers on the class type, because we
-  // don't yet keep track of whether a class type is a POD class type
-  // (or a "trivial" class type, as is used in C++0x).
   const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl());
   OverloadCandidateSet CandidateSet;
+
+  // Add constructors to the overload set.
+  OverloadedFunctionDecl *Constructors 
+    = const_cast<OverloadedFunctionDecl *>(ClassDecl->getConstructors());
+  for (OverloadedFunctionDecl::function_iterator Con 
+         = Constructors->function_begin();
+       Con != Constructors->function_end(); ++Con) {
+    CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
+    if ((Kind == IK_Direct) ||
+        (Kind == IK_Copy && Constructor->isConvertingConstructor()) ||
+        (Kind == IK_Default && Constructor->isDefaultConstructor()))
+      AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+  }
+
   OverloadCandidateSet::iterator Best;
-  AddOverloadCandidates(ClassDecl->getConstructors(), Args, NumArgs,
-                        CandidateSet);
   switch (BestViableFunction(CandidateSet, Best)) {
   case OR_Success:
     // We found a constructor. Return it.

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov  5 09:29:30 2008
@@ -1231,7 +1231,8 @@
                             literalExpr->getSourceRange().getEnd()));
   }
 
-  if (CheckInitializerTypes(literalExpr, literalType))
+  if (CheckInitializerTypes(literalExpr, literalType, LParenLoc, 
+                            "temporary"))
     return true;
 
   bool isFileScope = !getCurFunctionDecl() && !getCurMethodDecl();

Added: cfe/trunk/test/SemaCXX/copy-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/copy-initialization.cpp?rev=58756&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/copy-initialization.cpp (added)
+++ cfe/trunk/test/SemaCXX/copy-initialization.cpp Wed Nov  5 09:29:30 2008
@@ -0,0 +1,17 @@
+// RUN: clang -fsyntax-only -verify %s 
+
+class X {
+public:
+  explicit X(const X&);
+  X(int*); // expected-note{{candidate function}}
+  explicit X(float*);
+};
+
+class Y : public X { };
+
+void f(Y y, int *ip, float *fp) {
+  X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidates are:}}
+  X x2 = 0;
+  X x3 = ip;
+  X x4 = fp; // expected-error{{incompatible type initializing 'x4', expected 'class X'}}
+}

Propchange: cfe/trunk/test/SemaCXX/copy-initialization.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/copy-initialization.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaCXX/copy-initialization.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaCXX/direct-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/direct-initializer.cpp?rev=58756&r1=58755&r2=58756&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/direct-initializer.cpp (original)
+++ cfe/trunk/test/SemaCXX/direct-initializer.cpp Wed Nov  5 09:29:30 2008
@@ -20,9 +20,9 @@
   X(float, Y); // expected-note{{candidate function}}
 };
 
-class Z { // expected-note{{candidate function}}
+class Z {
 public:
-  Z(int); // expected-note{{candidate function}}
+  Z(int);
 };
 
 void g() {
@@ -32,5 +32,5 @@
   Y y(1.0);
   X x4(3.14, y);
 
-  Z z; // expected-error{{no matching constructor for initialization of 'z'; candidates are:}}
+  Z z; // expected-error{{no matching constructor for initialization of 'z'}}
 }





More information about the cfe-commits mailing list