]> granicus.if.org Git - clang/commitdiff
Implement user-defined conversions in InitializationSequence. WPI that
authorDouglas Gregor <dgregor@apple.com>
Mon, 14 Dec 2009 17:27:33 +0000 (17:27 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 14 Dec 2009 17:27:33 +0000 (17:27 +0000)
isn't turned on anyway yet, so it cannot be tested.

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

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

index e8794b14bc7e558084926e31e8fb3d597c27fe7a..44e1a77a0d75ddb0b0e910a629deeb7fe2f848f9 100644 (file)
@@ -2473,7 +2473,124 @@ static void TryUserDefinedConversion(Sema &S,
                                      const InitializationKind &Kind,
                                      Expr *Initializer,
                                      InitializationSequence &Sequence) {
-  // FIXME: Implement!
+  Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
+  
+  QualType DestType = Entity.getType().getType();
+  assert(!DestType->isReferenceType() && "References are handled elsewhere");
+  QualType SourceType = Initializer->getType();
+  assert((DestType->isRecordType() || SourceType->isRecordType()) &&
+         "Must have a class type to perform a user-defined conversion");
+  
+  // 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;
+  
+  if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) {
+    // The type we're converting to is a class type. Enumerate its constructors
+    // to see if there is a suitable conversion.
+    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,
+                                         &Initializer, 1, CandidateSet);
+        else
+          S.AddOverloadCandidate(Constructor, &Initializer, 1, CandidateSet);
+      }
+    }    
+  }
+  
+  if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) {
+    // The type we're converting from is a class type, enumerate its conversion
+    // functions.
+    CXXRecordDecl *SourceRecordDecl
+      = cast<CXXRecordDecl>(SourceRecordType->getDecl());
+    
+    const UnresolvedSet *Conversions
+      = SourceRecordDecl->getVisibleConversionFunctions();
+    for (UnresolvedSet::iterator I = Conversions->begin(),
+         E = Conversions->end(); 
+         I != E; ++I) {
+      NamedDecl *D = *I;
+      CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+      if (isa<UsingShadowDecl>(D))
+        D = cast<UsingShadowDecl>(D)->getTargetDecl();
+      
+      FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+      CXXConversionDecl *Conv;
+      if (ConvTemplate)
+        Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+      else
+        Conv = cast<CXXConversionDecl>(*I);
+      
+      if (AllowExplicit || !Conv->isExplicit()) {
+        if (ConvTemplate)
+          S.AddTemplateConversionCandidate(ConvTemplate, ActingDC, Initializer,
+                                           DestType, CandidateSet);
+        else
+          S.AddConversionCandidate(Conv, ActingDC, Initializer, DestType,
+                                   CandidateSet);
+      }
+    }
+  }
+  
+  SourceLocation DeclLoc = Initializer->getLocStart();
+  
+  // 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_UserConversionOverloadFailed, 
+                                Result);
+    return;
+  }
+  
+  FunctionDecl *Function = Best->Function;
+  
+  if (isa<CXXConstructorDecl>(Function)) {
+    // Add the user-defined conversion step. Any cv-qualification conversion is
+    // subsumed by the initialization.
+    Sequence.AddUserConversionStep(Function, DestType);
+    return;
+  }
+
+  // Add the user-defined conversion step that calls the conversion function.
+  QualType ConvType = Function->getResultType().getNonReferenceType();
+  Sequence.AddUserConversionStep(Function, ConvType);
+
+  // If the conversion following the call to the conversion function is 
+  // interesting, add it as a separate step.
+  if (Best->FinalConversion.First || Best->FinalConversion.Second ||
+      Best->FinalConversion.Third) {
+    ImplicitConversionSequence ICS;
+    ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+    ICS.Standard = Best->FinalConversion;
+    Sequence.AddConversionSequenceStep(ICS, DestType);
+  }
 }
 
 /// \brief Attempt an implicit conversion (C++ [conv]) converting from one
@@ -2604,7 +2721,7 @@ InitializationSequence::InitializationSequence(Sema &S,
   }
   
   //    - Otherwise, the initial value of the object being initialized is the
-  //      (possibly converted) value of the initializer expression. Standard
+  //      (possibly converted) value of the initializer expression. Standard
   //      conversions (Clause 4) will be used, if necessary, to convert the
   //      initializer expression to the cv-unqualified version of the 
   //      destination type; no user-defined conversions are considered.
@@ -2887,6 +3004,7 @@ bool InitializationSequence::Diagnose(Sema &S,
     break;
       
   case FK_ReferenceInitOverloadFailed:
+  case FK_UserConversionOverloadFailed:
     switch (FailedOverloadResult) {
     case OR_Ambiguous:
       S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
index a29159ace59934a5605aa3012cbc7a4fe38827a8..22484745da257a29c05e636613becbe77d8dead3 100644 (file)
@@ -303,6 +303,9 @@ public:
     /// dependently-type expressions.
     DependentSequence,
 
+    /// \brief A user-defined conversion sequence.
+    UserDefinedConversion,
+    
     /// \brief A reference binding.
     ReferenceBinding,
 
@@ -400,7 +403,9 @@ public:
     FK_ReferenceBindingToInitList,
     /// \brief Initialization of some unused destination type with an
     /// initializer list.
-    FK_InitListBadDestinationType
+    FK_InitListBadDestinationType,
+    /// \brief Overloading for a user-defined conversion failed.
+    FK_UserConversionOverloadFailed
   };
   
 private: