[cfe-commits] r58641 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/direct-initializer.cpp

Douglas Gregor doug.gregor at gmail.com
Mon Nov 3 12:45:28 PST 2008


Author: dgregor
Date: Mon Nov  3 14:45:27 2008
New Revision: 58641

URL: http://llvm.org/viewvc/llvm-project?rev=58641&view=rev
Log:
Implicit support for direct initialization of objects of class type, e.g.,

  X x(5, 7);



Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/direct-initializer.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58641&r1=58640&r2=58641&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Mon Nov  3 14:45:27 2008
@@ -835,6 +835,12 @@
      "call to '%0' is ambiguous; candidates are:")
 DIAG(err_ovl_candidate, NOTE,
      "candidate function")
+DIAG(err_ovl_no_viable_function_in_init, ERROR,
+     "no matching constructor for initialization of '%0'.")
+DIAG(err_ovl_no_viable_function_in_init_with_cands, ERROR,
+     "no matching constructor for initialization of '%0'; candidates are:")
+DIAG(err_ovl_ambiguous_init, ERROR,
+     "call to constructor of '%0' is ambiguous; candidates are:")
 
 DIAG(err_unexpected_typedef, ERROR,
      "unexpected type name '%0': expected expression")

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Nov  3 14:45:27 2008
@@ -418,7 +418,7 @@
                             Expr **Args, unsigned NumArgs,
                             OverloadCandidateSet& CandidateSet,
                             bool SuppressUserConversions = false);
-  void AddOverloadCandidates(OverloadedFunctionDecl *Ovl, 
+  void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl, 
                              Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet,
                              bool SuppressUserConversions = false);
@@ -710,6 +710,12 @@
                                              SourceLocation *CommaLocs,
                                              SourceLocation RParenLoc);
 
+  CXXConstructorDecl *
+  PerformDirectInitForClassType(QualType ClassType,
+                                Expr **Args, unsigned NumArgs,
+                                SourceLocation Loc, SourceRange Range,
+                                std::string InitEntity, bool HasInitializer);
+
   /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
   virtual ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
                                        SourceLocation LAngleBracketLoc, TypeTy *Ty,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Nov  3 14:45:27 2008
@@ -1621,11 +1621,37 @@
     //   function return type, in the declaration of a class member
     //   within its class declaration (9.2), and where the extern
     //   specifier is explicitly used.
-    if (Type->isReferenceType() && Var->getStorageClass() != VarDecl::Extern)
+    if (Type->isReferenceType() && Var->getStorageClass() != VarDecl::Extern) {
       Diag(Var->getLocation(),
            diag::err_reference_var_requires_init,
            Var->getName(), 
            SourceRange(Var->getLocation(), Var->getLocation()));
+      Var->setInvalidDecl();
+      return;
+    }
+
+    // C++ [dcl.init]p9:
+    //
+    //   If no initializer is specified for an object, and the object
+    //   is of (possibly cv-qualified) non-POD class type (or array
+    //   thereof), the object shall be default-initialized; if the
+    //   object is of const-qualified type, the underlying class type
+    //   shall have a user-declared default constructor.
+    if (getLangOptions().CPlusPlus) {
+      QualType InitType = Type;
+      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);
+        if (!Constructor)
+          Var->setInvalidDecl();
+      }
+    }
 
 #if 0
     // FIXME: Temporarily disabled because we are not properly parsing

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Nov  3 14:45:27 2008
@@ -848,14 +848,21 @@
   // The form of initialization (using parentheses or '=') is generally
   // insignificant, but does matter when the entity being initialized has a
   // class type.
+  QualType DeclInitType = VDecl->getType();
+  if (const ArrayType *Array = Context.getAsArrayType(DeclInitType))
+    DeclInitType = Array->getElementType();
 
   if (VDecl->getType()->isRecordType()) {
-    // FIXME: When constructors for class types are supported, determine how 
-    // exactly semantic checking will be done for direct initializers.
-    unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error,
-                           "initialization for class types is not handled yet");
-    Diag(VDecl->getLocation(), DiagID);
-    RealDecl->setInvalidDecl();
+    CXXConstructorDecl *Constructor
+      = PerformDirectInitForClassType(DeclInitType, (Expr **)ExprTys, NumExprs,
+                                      VDecl->getLocation(),
+                                      SourceRange(VDecl->getLocation(),
+                                                  RParenLoc),
+                                      VDecl->getName(),
+                                      /*HasInitializer=*/true);
+    if (!Constructor) {
+      RealDecl->setInvalidDecl();
+    }
     return;
   }
 
@@ -874,6 +881,71 @@
   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
+/// the constructor that will be used to perform the initialization;
+/// 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) {
+  const RecordType *ClassRec = ClassType->getAsRecordType();
+  assert(ClassRec && "Can only initialize a class type here");
+
+  // C++ [dcl.init]p14: 
+  //
+  //   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. The
+  //   applicable constructors are enumerated (13.3.1.3), and the
+  //   best one is chosen through overload resolution (13.3). The
+  //   constructor so selected is called to initialize the object,
+  //   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;
+  OverloadCandidateSet::iterator Best;
+  AddOverloadCandidates(ClassDecl->getConstructors(), Args, NumArgs,
+                        CandidateSet);
+  switch (BestViableFunction(CandidateSet, Best)) {
+  case OR_Success:
+    // We found a constructor. Return it.
+    return cast<CXXConstructorDecl>(Best->Function);
+    
+  case OR_No_Viable_Function:
+    if (CandidateSet.empty())
+      Diag(Loc, diag::err_ovl_no_viable_function_in_init, 
+           InitEntity, Range);
+    else {
+      Diag(Loc, diag::err_ovl_no_viable_function_in_init_with_cands, 
+           InitEntity, Range);
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+    }
+    return 0;
+    
+  case OR_Ambiguous:
+    Diag(Loc, diag::err_ovl_ambiguous_init, 
+         InitEntity, Range);
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+    return 0;
+  }
+  
+  return 0;
+}
+
 /// CompareReferenceRelationship - Compare the two types T1 and T2 to
 /// determine whether they are reference-related,
 /// reference-compatible, reference-compatible with added

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Nov  3 14:45:27 2008
@@ -1435,12 +1435,13 @@
 /// AddOverloadCandidates - Add all of the function overloads in Ovl
 /// to the candidate set.
 void 
-Sema::AddOverloadCandidates(OverloadedFunctionDecl *Ovl, 
+Sema::AddOverloadCandidates(const OverloadedFunctionDecl *Ovl, 
                             Expr **Args, unsigned NumArgs,
                             OverloadCandidateSet& CandidateSet,
                             bool SuppressUserConversions)
 {
-  for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin();
+  for (OverloadedFunctionDecl::function_const_iterator Func 
+         = Ovl->function_begin();
        Func != Ovl->function_end(); ++Func)
     AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet,
                          SuppressUserConversions);

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

==============================================================================
--- cfe/trunk/test/SemaCXX/direct-initializer.cpp (original)
+++ cfe/trunk/test/SemaCXX/direct-initializer.cpp Mon Nov  3 14:45:27 2008
@@ -8,3 +8,29 @@
   int (x2)(1); // expected-warning {{statement was disambiguated as declaration}}
   for (int x(1);;) {}
 }
+
+class Y { 
+  explicit Y(float);
+};
+
+class X { // expected-note{{candidate function}}
+public:
+  explicit X(int); // expected-note{{candidate function}}
+  X(float, float, float); // expected-note{{candidate function}}
+  X(float, Y); // expected-note{{candidate function}}
+};
+
+class Z { // expected-note{{candidate function}}
+public:
+  Z(int); // expected-note{{candidate function}}
+};
+
+void g() {
+  X x1(5);
+  X x2(1.0, 3, 4.2);
+  X x3(1.0, 1.0); // expected-error{{no matching constructor for initialization of 'x3'; candidates are:}}
+  Y y(1.0);
+  X x4(3.14, y);
+
+  Z z; // expected-error{{no matching constructor for initialization of 'z'; candidates are:}}
+}





More information about the cfe-commits mailing list