[cfe-commits] r58870 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/user-defined-conversions.cpp

Douglas Gregor doug.gregor at gmail.com
Fri Nov 7 14:36:19 PST 2008


Author: dgregor
Date: Fri Nov  7 16:36:19 2008
New Revision: 58870

URL: http://llvm.org/viewvc/llvm-project?rev=58870&view=rev
Log:
Initial, partially-baked support for implicit user-defined conversions by conversion functions

Added:
    cfe/trunk/test/SemaCXX/user-defined-conversions.cpp   (with props)
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaOverload.h

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Nov  7 16:36:19 2008
@@ -417,6 +417,9 @@
                             Expr **Args, unsigned NumArgs,
                             OverloadCandidateSet& CandidateSet,
                             bool SuppressUserConversions = false);
+  void AddConversionCandidate(CXXConversionDecl *Conversion,
+                              Expr *From, QualType ToType,
+                              OverloadCandidateSet& CandidateSet);
   void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl, 
                              Expr **Args, unsigned NumArgs,
                              OverloadCandidateSet& CandidateSet,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Nov  7 16:36:19 2008
@@ -893,7 +893,20 @@
     }
   }
 
-  // FIXME: Implement support for user-defined conversion operators.
+  if (const CXXRecordType *FromRecordType
+        = dyn_cast_or_null<CXXRecordType>(From->getType()->getAsRecordType())) {
+    // Add all of the conversion functions as candidates.
+    // FIXME: Look for conversions in base classes!
+    CXXRecordDecl *FromRecordDecl = FromRecordType->getDecl();
+    OverloadedFunctionDecl *Conversions 
+      = FromRecordDecl->getConversionFunctions();
+    for (OverloadedFunctionDecl::function_iterator Func 
+           = Conversions->function_begin();
+         Func != Conversions->function_end(); ++Func) {
+      CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+      AddConversionCandidate(Conv, From, ToType, CandidateSet);
+    }
+  }
 
   OverloadCandidateSet::iterator Best;
   switch (BestViableFunction(CandidateSet, Best)) {
@@ -917,9 +930,30 @@
           = ThisType->getAsPointerType()->getPointeeType().getAsOpaquePtr();
         User.After.ToTypePtr = ToType.getAsOpaquePtr();
         return true;
+      } else if (CXXConversionDecl *Conversion
+                   = dyn_cast<CXXConversionDecl>(Best->Function)) {
+        // C++ [over.ics.user]p1:
+        //
+        //   [...] If the user-defined conversion is specified by a
+        //   conversion function (12.3.2), the initial standard
+        //   conversion sequence converts the source type to the
+        //   implicit object parameter of the conversion function.
+        User.Before = Best->Conversions[0].Standard;
+        User.ConversionFunction = Conversion;
+        
+        // C++ [over.ics.user]p2: 
+        //   The second standard conversion sequence converts the
+        //   result of the user-defined conversion to the target type
+        //   for the sequence. Since an implicit conversion sequence
+        //   is an initialization, the special rules for
+        //   initialization by user-defined conversion apply when
+        //   selecting the best user-defined conversion for a
+        //   user-defined conversion sequence (see 13.3.3 and
+        //   13.3.3.1).
+        User.After = Best->FinalConversion;
+        return true;
       } else {
-        assert(false && 
-               "Cannot perform user-defined conversion via a conversion operator");
+        assert(false && "Not a constructor or conversion function?");
         return false;
       }
       
@@ -1378,6 +1412,8 @@
   const FunctionTypeProto* Proto 
     = dyn_cast<FunctionTypeProto>(Function->getType()->getAsFunctionType());
   assert(Proto && "Functions without a prototype cannot be overloaded");
+  assert(!isa<CXXConversionDecl>(Function) && 
+         "Use AddConversionCandidate for conversion functions");
 
   // Add this candidate
   CandidateSet.push_back(OverloadCandidate());
@@ -1433,6 +1469,76 @@
   }
 }
 
+/// AddConversionCandidate - Add a C++ conversion function as a
+/// candidate in the candidate set (C++ [over.match.conv], 
+/// C++ [over.match.copy]). From is the expression we're converting from,
+/// and ToType is the type that we're eventually trying to convert to 
+/// (which may or may not be the same type as the type that the
+/// conversion function produces).
+void
+Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
+                             Expr *From, QualType ToType,
+                             OverloadCandidateSet& CandidateSet) {
+  // Add this candidate
+  CandidateSet.push_back(OverloadCandidate());
+  OverloadCandidate& Candidate = CandidateSet.back();
+  Candidate.Function = Conversion;
+  Candidate.FinalConversion.setAsIdentityConversion();
+  Candidate.FinalConversion.FromTypePtr 
+    = Conversion->getConversionType().getAsOpaquePtr();
+  Candidate.FinalConversion.ToTypePtr = ToType.getAsOpaquePtr();
+
+  // Determine the implicit conversion sequences for each of the
+  // arguments.
+  Candidate.Viable = true;
+  Candidate.Conversions.resize(1);
+
+  // FIXME: We need to follow the rules for the implicit object
+  // parameter.
+  QualType ImplicitObjectType 
+    = Context.getTypeDeclType(Conversion->getParent());
+  ImplicitObjectType 
+    = ImplicitObjectType.getQualifiedType(Conversion->getTypeQualifiers());
+  ImplicitObjectType = Context.getReferenceType(ImplicitObjectType);
+  Candidate.Conversions[0] = TryCopyInitialization(From, ImplicitObjectType, 
+                                                   true);
+  if (Candidate.Conversions[0].ConversionKind 
+      == ImplicitConversionSequence::BadConversion) {
+    Candidate.Viable = false;
+    return;
+  }
+
+  // To determine what the conversion from the result of calling the
+  // conversion function to the type we're eventually trying to
+  // convert to (ToType), we need to synthesize a call to the
+  // conversion function and attempt copy initialization from it. This
+  // makes sure that we get the right semantics with respect to
+  // lvalues/rvalues and the type. Fortunately, we can allocate this
+  // call on the stack and we don't need its arguments to be
+  // well-formed.
+  DeclRefExpr ConversionRef(Conversion, Conversion->getType(), 
+                            SourceLocation());
+  ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
+                                &ConversionRef);
+  CallExpr Call(&ConversionFn, 0, 0, 
+                Conversion->getConversionType().getNonReferenceType(),
+                SourceLocation());
+  ImplicitConversionSequence ICS = TryCopyInitialization(&Call, ToType, true);
+  switch (ICS.ConversionKind) {
+  case ImplicitConversionSequence::StandardConversion:
+    Candidate.FinalConversion = ICS.Standard;
+    break;
+
+  case ImplicitConversionSequence::BadConversion:
+    Candidate.Viable = false;
+    break;
+
+  default:
+    assert(false && 
+           "Can only end up with a standard conversion sequence or failure");
+  }
+}
+
 /// AddOverloadCandidates - Add all of the function overloads in Ovl
 /// to the candidate set.
 void 
@@ -1494,6 +1600,32 @@
 
   // FIXME: Several other bullets in (C++ 13.3.3p1) need to be implemented.
 
+  // C++ [over.match.best]p1b4:
+  //
+  //   -- the context is an initialization by user-defined conversion
+  //      (see 8.5, 13.3.1.5) and the standard conversion sequence
+  //      from the return type of F1 to the destination type (i.e.,
+  //      the type of the entity being initialized) is a better
+  //      conversion sequence than the standard conversion sequence
+  //      from the return type of F2 to the destination type.
+  if (isa<CXXConversionDecl>(Cand1.Function) && 
+      isa<CXXConversionDecl>(Cand2.Function)) {
+    switch (CompareStandardConversionSequences(Cand1.FinalConversion,
+                                               Cand2.FinalConversion)) {
+    case ImplicitConversionSequence::Better:
+      // Cand1 has a better conversion sequence.
+      return true;
+
+    case ImplicitConversionSequence::Worse:
+      // Cand1 can't be better than Cand2.
+      return false;
+
+    case ImplicitConversionSequence::Indistinguishable:
+      // Do nothing
+      break;
+    }
+  }
+
   return false;
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Fri Nov  7 16:36:19 2008
@@ -207,6 +207,12 @@
 
     /// Viable - True to indicate that this overload candidate is viable.
     bool Viable;
+
+    /// FinalConversion - For a conversion function (where Function is
+    /// a CXXConversionDecl), the standard conversion that occurs
+    /// after the call to the overload candidate to convert the result
+    /// of calling the conversion function to the required type.
+    StandardConversionSequence FinalConversion;
   };
 
   /// OverloadCandidateSet - A set of overload candidates, used in C++

Added: cfe/trunk/test/SemaCXX/user-defined-conversions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/user-defined-conversions.cpp?rev=58870&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/user-defined-conversions.cpp (added)
+++ cfe/trunk/test/SemaCXX/user-defined-conversions.cpp Fri Nov  7 16:36:19 2008
@@ -0,0 +1,22 @@
+// RUN: clang -fsyntax-only -verify %s 
+struct X {
+  operator bool();
+};
+
+int& f(bool);
+float& f(int);
+
+void f_test(X x) {
+  int& i1 = f(x);
+}
+
+struct Y {
+  operator short();
+  operator float();
+};
+
+void g(int);
+
+void g_test(Y y) {
+  g(y);
+}

Propchange: cfe/trunk/test/SemaCXX/user-defined-conversions.cpp

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

Propchange: cfe/trunk/test/SemaCXX/user-defined-conversions.cpp

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

Propchange: cfe/trunk/test/SemaCXX/user-defined-conversions.cpp

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





More information about the cfe-commits mailing list