[cfe-commits] r91323 - in /cfe/trunk/lib/Sema: SemaInit.cpp SemaInit.h

Douglas Gregor dgregor at apple.com
Mon Dec 14 12:49:28 PST 2009


Author: dgregor
Date: Mon Dec 14 14:49:26 2009
New Revision: 91323

URL: http://llvm.org/viewvc/llvm-project?rev=91323&view=rev
Log:
Constructor initialization for InitializationSequence. Untested WIP.

Modified:
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaInit.h

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Mon Dec 14 14:49:26 2009
@@ -1969,6 +1969,7 @@
   case SK_QualificationConversionRValue:
   case SK_QualificationConversionLValue:
   case SK_ListInitialization:
+  case SK_ConstructorInitialization:
     break;
     
   case SK_ConversionSequence:
@@ -2036,6 +2037,17 @@
   Steps.push_back(S);
 }
 
+void 
+InitializationSequence::AddConstructorInitializationStep(
+                                              CXXConstructorDecl *Constructor,
+                                                         QualType T) {
+  Step S;
+  S.Kind = SK_ConstructorInitialization;
+  S.Type = T;
+  S.Function = Constructor;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::SetOverloadFailure(FailureKind Failure, 
                                                 OverloadingResult Result) {
   SequenceKind = FailedSequence;
@@ -2462,7 +2474,70 @@
                                          const InitializationKind &Kind,
                                          Expr **Args, unsigned NumArgs,
                                          InitializationSequence &Sequence) {
-  // FIXME: Implement!
+  Sequence.setSequenceKind(InitializationSequence::ConstructorConversion);
+  
+  // Build the candidate set directly in the initialization sequence
+  // structure, so that it will persist if we fail.
+  OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
+  CandidateSet.clear();
+  
+  // Determine whether we are allowed to call explicit constructors or
+  // explicit conversion operators.
+  bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
+                        Kind.getKind() == InitializationKind::IK_Value ||
+                        Kind.getKind() == InitializationKind::IK_Default);                      
+  
+  // The type we're converting to is a class type. Enumerate its constructors
+  // to see if one is suitable.
+  QualType DestType = Entity.getType().getType();
+  const RecordType *DestRecordType = DestType->getAs<RecordType>();
+  assert(DestRecordType && "Constructor initialization requires record type");  
+  CXXRecordDecl *DestRecordDecl
+    = cast<CXXRecordDecl>(DestRecordType->getDecl());
+    
+  DeclarationName ConstructorName
+    = S.Context.DeclarationNames.getCXXConstructorName(
+                     S.Context.getCanonicalType(DestType).getUnqualifiedType());
+  DeclContext::lookup_iterator Con, ConEnd;
+  for (llvm::tie(Con, ConEnd) = DestRecordDecl->lookup(ConstructorName);
+       Con != ConEnd; ++Con) {
+    // Find the constructor (which may be a template).
+    CXXConstructorDecl *Constructor = 0;
+    FunctionTemplateDecl *ConstructorTmpl
+      = dyn_cast<FunctionTemplateDecl>(*Con);
+    if (ConstructorTmpl)
+      Constructor = cast<CXXConstructorDecl>(
+                                           ConstructorTmpl->getTemplatedDecl());
+    else
+      Constructor = cast<CXXConstructorDecl>(*Con);
+    
+    if (!Constructor->isInvalidDecl() &&
+        Constructor->isConvertingConstructor(AllowExplicit)) {
+      if (ConstructorTmpl)
+        S.AddTemplateOverloadCandidate(ConstructorTmpl, /*ExplicitArgs*/ 0,
+                                       Args, NumArgs, CandidateSet);
+      else
+        S.AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet);
+    }
+  }    
+    
+  SourceLocation DeclLoc = Kind.getLocation();
+  
+  // Perform overload resolution. If it fails, return the failed result.  
+  OverloadCandidateSet::iterator Best;
+  if (OverloadingResult Result 
+        = S.BestViableFunction(CandidateSet, DeclLoc, Best)) {
+    Sequence.SetOverloadFailure(
+                          InitializationSequence::FK_ConstructorOverloadFailed, 
+                                Result);
+    return;
+  }
+  
+  // Add the constructor initialization step. Any cv-qualification conversion is
+  // subsumed by the initialization.
+  Sequence.AddConstructorInitializationStep(
+                                      cast<CXXConstructorDecl>(Best->Function), 
+                                            DestType);
 }
 
 /// \brief Attempt a user-defined conversion between two types (C++ [dcl.init]),
@@ -2968,6 +3043,30 @@
       CurInit = S.Owned(InitList);
       break;
     }
+
+    case SK_ConstructorInitialization: {
+      CXXConstructorDecl *Constructor
+        = cast<CXXConstructorDecl>(Step->Function);
+      
+      // Build a call to the selected constructor.
+      ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
+      SourceLocation Loc = Kind.getLocation();
+          
+      // Determine the arguments required to actually perform the constructor
+      // call.
+      if (S.CompleteConstructorCall(Constructor, move(Args), 
+                                    Loc, ConstructorArgs))
+        return S.ExprError();
+          
+      // Build the an expression that constructs a temporary.
+      CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, 
+                                        move_arg(ConstructorArgs));
+      if (CurInit.isInvalid())
+        return S.ExprError();
+          
+      CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+      break;
+    }
     }
   }
   
@@ -3101,6 +3200,50 @@
     S.Diag(Kind.getLocation(), diag::err_init_list_bad_dest_type)
       << (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
     break;
+      
+  case FK_ConstructorOverloadFailed: {
+    SourceRange ArgsRange;
+    if (NumArgs)
+      ArgsRange = SourceRange(Args[0]->getLocStart(), 
+                              Args[NumArgs - 1]->getLocEnd());
+    
+    // FIXME: Using "DestType" for the entity we're printing is probably
+    // bad.
+    switch (FailedOverloadResult) {
+      case OR_Ambiguous:
+        S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init)
+          << DestType << ArgsRange;
+        S.PrintOverloadCandidates(FailedCandidateSet, true);
+        break;
+        
+      case OR_No_Viable_Function:
+        S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init)
+          << DestType << ArgsRange;
+        S.PrintOverloadCandidates(FailedCandidateSet, false);
+        break;
+        
+      case OR_Deleted: {
+        S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
+          << true << DestType << ArgsRange;
+        OverloadCandidateSet::iterator Best;
+        OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet,
+                                                     Kind.getLocation(),
+                                                     Best);
+        if (Ovl == OR_Deleted) {
+          S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
+            << Best->Function->isDeleted();
+        } else {
+          llvm_unreachable("Inconsistent overload resolution?");
+        }
+        break;
+      }
+        
+      case OR_Success:
+        llvm_unreachable("Conversion did not fail!");
+        break;
+    }
+    break;
+  }
   }
   
   return true;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.h (original)
+++ cfe/trunk/lib/Sema/SemaInit.h Mon Dec 14 14:49:26 2009
@@ -306,6 +306,9 @@
     /// \brief A user-defined conversion sequence.
     UserDefinedConversion,
     
+    /// \brief A constructor call.
+    ConstructorConversion,
+    
     /// \brief A reference binding.
     ReferenceBinding,
 
@@ -337,7 +340,9 @@
     /// \brief Perform an implicit conversion sequence.
     SK_ConversionSequence,
     /// \brief Perform list-initialization
-    SK_ListInitialization
+    SK_ListInitialization,
+    /// \brief Perform initialization via a constructor.
+    SK_ConstructorInitialization
   };
   
   /// \brief A single step in the initialization sequence.
@@ -405,7 +410,9 @@
     /// initializer list.
     FK_InitListBadDestinationType,
     /// \brief Overloading for a user-defined conversion failed.
-    FK_UserConversionOverloadFailed
+    FK_UserConversionOverloadFailed,
+    /// \brief Overloaded for initialization by constructor failed.
+    FK_ConstructorOverloadFailed
   };
   
 private:
@@ -529,6 +536,10 @@
   /// \brief Add a list-initialiation step  
   void AddListInitializationStep(QualType T);
 
+  /// \brief Add a a constructor-initialization step.
+  void AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
+                                        QualType T);
+  
   /// \brief Note that this initialization sequence failed.
   void SetFailed(FailureKind Failure) {
     SequenceKind = FailedSequence;





More information about the cfe-commits mailing list