[cfe-commits] r58629 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaOverload.h test/SemaCXX/converting-constructor.cpp test/SemaCXX/overload-call-copycon.cpp

Douglas Gregor doug.gregor at gmail.com
Mon Nov 3 11:09:14 PST 2008


Author: dgregor
Date: Mon Nov  3 13:09:14 2008
New Revision: 58629

URL: http://llvm.org/viewvc/llvm-project?rev=58629&view=rev
Log:
Standard conversion sequences now have a CopyConstructor field, to
cope with the case where a user-defined conversion is actually a copy
construction, and therefore can be compared against other standard
conversion sequences. While I called this a hack before, now I'm
convinced that it's the right way to go.

Compare overloads based on derived-to-base conversions that invoke
copy constructors. 

Suppress user-defined conversions when attempting to call a
user-defined conversion.


Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaOverload.h
    cfe/trunk/test/SemaCXX/converting-constructor.cpp
    cfe/trunk/test/SemaCXX/overload-call-copycon.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Nov  3 13:09:14 2008
@@ -370,7 +370,9 @@
   /// C++ Overloading.
   bool IsOverload(FunctionDecl *New, Decl* OldD, 
                   OverloadedFunctionDecl::function_iterator &MatchedDecl);
-  ImplicitConversionSequence TryImplicitConversion(Expr* From, QualType ToType);
+  ImplicitConversionSequence 
+  TryImplicitConversion(Expr* From, QualType ToType,
+                        bool SuppressUserConversions = false);
   bool IsStandardConversion(Expr *From, QualType ToType, 
                             StandardConversionSequence& SCS);
   bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
@@ -398,7 +400,9 @@
   CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
                                   const StandardConversionSequence& SCS2);
 
-  ImplicitConversionSequence TryCopyInitialization(Expr* From, QualType ToType);
+  ImplicitConversionSequence 
+  TryCopyInitialization(Expr* From, QualType ToType,
+                        bool SuppressUserConversions = false);
   bool PerformCopyInitialization(Expr *&From, QualType ToType, 
                                  const char *Flavor);
 
@@ -412,10 +416,12 @@
 
   void AddOverloadCandidate(FunctionDecl *Function, 
                             Expr **Args, unsigned NumArgs,
-                            OverloadCandidateSet& CandidateSet);
+                            OverloadCandidateSet& CandidateSet,
+                            bool SuppressUserConversions = false);
   void AddOverloadCandidates(OverloadedFunctionDecl *Ovl, 
                              Expr **Args, unsigned NumArgs,
-                             OverloadCandidateSet& CandidateSet);
+                             OverloadCandidateSet& CandidateSet,
+                             bool SuppressUserConversions = false);
   bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
                                  const OverloadCandidate& Cand2);
   OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
@@ -1165,7 +1171,8 @@
                                                       bool& DerivedToBase);
 
   bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
-                          ImplicitConversionSequence *ICS = 0);
+                          ImplicitConversionSequence *ICS = 0,
+                          bool SuppressUserConversions = false);
 
   /// CheckCastTypes - Check type constraints for casting between types.
   bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Nov  3 13:09:14 2008
@@ -931,9 +931,13 @@
 /// errors are found. Either way, a return value of true indicates
 /// that there was a failure, a return value of false indicates that
 /// the reference initialization succeeded.
+///
+/// When @p SuppressUserConversions, user-defined conversions are
+/// suppressed.
 bool 
 Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, 
-                         ImplicitConversionSequence *ICS) {
+                         ImplicitConversionSequence *ICS,
+                         bool SuppressUserConversions) {
   assert(DeclType->isReferenceType() && "Reference init needs a reference");
 
   QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
@@ -1114,7 +1118,7 @@
     ///   the argument expression. Any difference in top-level
     ///   cv-qualification is subsumed by the initialization itself
     ///   and does not constitute a conversion.
-    *ICS = TryImplicitConversion(Init, T1);
+    *ICS = TryImplicitConversion(Init, T1, SuppressUserConversions);
     return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
   } else {
     return PerformImplicitConversion(Init, T1);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Nov  3 13:09:14 2008
@@ -929,6 +929,13 @@
   // anything here.
   QualType FromType = From->getType();
 
+  if (SCS.CopyConstructor) {
+    // FIXME: Create a temporary object by calling the copy
+    // constructor.
+    ImpCastExprToType(From, ToType);
+    return false;
+  }
+
   // Perform the first implicit conversion.
   switch (SCS.First) {
   case ICK_Identity:
@@ -982,13 +989,6 @@
     ImpCastExprToType(From, FromType);
     break;
 
-  case ICK_Derived_To_Base:
-    // FIXME: This should never happen. It's a consequence of
-    // pretending that a user-defined conversion via copy constructor
-    // is actually a standard conversion.
-    ImpCastExprToType(From, ToType);
-    break;
-
   default:
     assert(false && "Improper second standard conversion");
     break;

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Nov  3 13:09:14 2008
@@ -99,6 +99,7 @@
   Deprecated = false;
   ReferenceBinding = false;
   DirectBinding = false;
+  CopyConstructor = 0;
 }
 
 /// getRank - Retrieve the rank of this standard conversion sequence
@@ -174,6 +175,14 @@
       fprintf(stderr, " -> ");
     }
     fprintf(stderr, "%s", GetImplicitConversionName(Second));
+
+    if (CopyConstructor) {
+      fprintf(stderr, " (by copy constructor)");
+    } else if (DirectBinding) {
+      fprintf(stderr, " (direct reference binding)");
+    } else if (ReferenceBinding) {
+      fprintf(stderr, " (reference binding)");
+    }
     PrintedSomething = true;
   }
 
@@ -344,13 +353,18 @@
 /// it will not produce any diagnostics if no conversion is available,
 /// but will instead return an implicit conversion sequence of kind
 /// "BadConversion".
+///
+/// If @p SuppressUserConversions, then user-defined conversions are
+/// not permitted.
 ImplicitConversionSequence
-Sema::TryImplicitConversion(Expr* From, QualType ToType)
+Sema::TryImplicitConversion(Expr* From, QualType ToType,
+                            bool SuppressUserConversions)
 {
   ImplicitConversionSequence ICS;
   if (IsStandardConversion(From, ToType, ICS.Standard))
     ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
-  else if (IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
+  else if (!SuppressUserConversions &&
+           IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
     ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
     // C++ [over.ics.user]p4:
     //   A conversion of an expression of class type to the same class
@@ -362,15 +376,13 @@
     if (CXXConstructorDecl *Constructor 
           = dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
       if (Constructor->isCopyConstructor(Context)) {
-        // FIXME: This is a temporary hack to give copy-constructor
-        // calls the appropriate rank (Exact Match or Conversion) by
-        // making them into standard conversions. To really fix this, we
-        // need to tweak the rank-checking logic to deal with ranking
-        // different kinds of user conversions.
+        // Turn this into a "standard" conversion sequence, so that it
+        // gets ranked with standard conversion sequences.
         ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
         ICS.Standard.setAsIdentityConversion();
         ICS.Standard.FromTypePtr = From->getType().getAsOpaquePtr();
         ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
+        ICS.Standard.CopyConstructor = Constructor;
         if (IsDerivedFrom(From->getType().getUnqualifiedType(),
                           ToType.getUnqualifiedType()))
           ICS.Standard.Second = ICK_Derived_To_Base;
@@ -403,6 +415,7 @@
   // Standard conversions (C++ [conv])
   SCS.Deprecated = false;
   SCS.FromTypePtr = FromType.getAsOpaquePtr();
+  SCS.CopyConstructor = 0;
 
   // The first conversion can be an lvalue-to-rvalue conversion,
   // array-to-pointer conversion, or function-to-pointer conversion
@@ -536,13 +549,6 @@
     //   [...] Any difference in top-level cv-qualification is
     //   subsumed by the initialization itself and does not constitute
     //   a conversion. [...]
-
-    // C++ [dcl.init]p14 last bullet:
-    //   [ Note: an expression of type "cv1 T" can initialize an object
-    //   of type “cv2 T” independently of the cv-qualifiers cv1 and
-    //   cv2. -- end note]
-    //
-    // FIXME: Where is the normative text?
     CanonFrom = Context.getCanonicalType(FromType);
     CanonTo = Context.getCanonicalType(ToType);    
     if (CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() &&
@@ -881,8 +887,8 @@
          func != Constructors->function_end(); ++func) {
       CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*func);
       if (Constructor->isConvertingConstructor())
-        // FIXME: Suppress user-defined conversions in here!
-        AddOverloadCandidate(Constructor, &From, 1, CandidateSet);
+        AddOverloadCandidate(Constructor, &From, 1, CandidateSet,
+                             /*SuppressUserConversions=*/true);
     }
   }
 
@@ -1259,9 +1265,9 @@
         return ImplicitConversionSequence::Worse;
     }
 
-    //     -- binding of an expression of type B to a reference of type
-    //        A& is better than binding an expression of type C to a
-    //        reference of type A&,
+    //   -- binding of an expression of type B to a reference of type
+    //      A& is better than binding an expression of type C to a
+    //      reference of type A&,
     if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
         ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
       if (IsDerivedFrom(FromType2, FromType1))
@@ -1278,9 +1284,26 @@
   // FIXME: conversion of B::* to C::* is better than conversion of
   // A::* to C::*, and
 
-  // FIXME: conversion of C to B is better than conversion of C to A,
+  if (SCS1.CopyConstructor && SCS2.CopyConstructor &&
+      SCS1.Second == ICK_Derived_To_Base) {
+    //   -- conversion of C to B is better than conversion of C to A,
+    if (FromType1.getUnqualifiedType() == FromType2.getUnqualifiedType() &&
+        ToType1.getUnqualifiedType() != ToType2.getUnqualifiedType()) {
+      if (IsDerivedFrom(ToType1, ToType2))
+        return ImplicitConversionSequence::Better;
+      else if (IsDerivedFrom(ToType2, ToType1))
+        return ImplicitConversionSequence::Worse;
+    }
 
-  // FIXME: conversion of B to A is better than conversion of C to A.
+    //   -- conversion of B to A is better than conversion of C to A.
+    if (FromType1.getUnqualifiedType() != FromType2.getUnqualifiedType() &&
+        ToType1.getUnqualifiedType() == ToType2.getUnqualifiedType()) {
+      if (IsDerivedFrom(FromType2, FromType1))
+        return ImplicitConversionSequence::Better;
+      else if (IsDerivedFrom(FromType1, FromType2))
+        return ImplicitConversionSequence::Worse;
+    }
+  }
 
   return ImplicitConversionSequence::Indistinguishable;
 }
@@ -1289,9 +1312,11 @@
 /// ToType from the expression From. Return the implicit conversion
 /// sequence required to pass this argument, which may be a bad
 /// conversion sequence (meaning that the argument cannot be passed to
-/// a parameter of this type). This is user for argument passing, 
+/// a parameter of this type). If @p SuppressUserConversions, then we
+/// do not permit any user-defined conversion sequences.
 ImplicitConversionSequence 
-Sema::TryCopyInitialization(Expr *From, QualType ToType) {
+Sema::TryCopyInitialization(Expr *From, QualType ToType, 
+                            bool SuppressUserConversions) {
   if (!getLangOptions().CPlusPlus) {
     // In C, copy initialization is the same as performing an assignment.
     AssignConvertType ConvTy =
@@ -1305,10 +1330,10 @@
     return ICS;
   } else if (ToType->isReferenceType()) {
     ImplicitConversionSequence ICS;
-    CheckReferenceInit(From, ToType, &ICS);
+    CheckReferenceInit(From, ToType, &ICS, SuppressUserConversions);
     return ICS;
   } else {
-    return TryImplicitConversion(From, ToType);
+    return TryImplicitConversion(From, ToType, SuppressUserConversions);
   }
 }
 
@@ -1340,11 +1365,14 @@
 }
 
 /// AddOverloadCandidate - Adds the given function to the set of
-/// candidate functions, using the given function call arguments.
+/// candidate functions, using the given function call arguments.  If
+/// @p SuppressUserConversions, then don't allow user-defined
+/// conversions via constructors or conversion operators.
 void 
 Sema::AddOverloadCandidate(FunctionDecl *Function, 
                            Expr **Args, unsigned NumArgs,
-                           OverloadCandidateSet& CandidateSet)
+                           OverloadCandidateSet& CandidateSet,
+                           bool SuppressUserConversions)
 {
   const FunctionTypeProto* Proto 
     = dyn_cast<FunctionTypeProto>(Function->getType()->getAsFunctionType());
@@ -1389,7 +1417,8 @@
       // parameter of F.
       QualType ParamType = Proto->getArgType(ArgIdx);
       Candidate.Conversions[ArgIdx] 
-        = TryCopyInitialization(Args[ArgIdx], ParamType);
+        = TryCopyInitialization(Args[ArgIdx], ParamType, 
+                                SuppressUserConversions);
       if (Candidate.Conversions[ArgIdx].ConversionKind 
             == ImplicitConversionSequence::BadConversion)
         Candidate.Viable = false;
@@ -1408,11 +1437,13 @@
 void 
 Sema::AddOverloadCandidates(OverloadedFunctionDecl *Ovl, 
                             Expr **Args, unsigned NumArgs,
-                            OverloadCandidateSet& CandidateSet)
+                            OverloadCandidateSet& CandidateSet,
+                            bool SuppressUserConversions)
 {
   for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin();
        Func != Ovl->function_end(); ++Func)
-    AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
+    AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet,
+                         SuppressUserConversions);
 }
 
 /// isBetterOverloadCandidate - Determines whether the first overload

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.h (original)
+++ cfe/trunk/lib/Sema/SemaOverload.h Mon Nov  3 13:09:14 2008
@@ -18,6 +18,7 @@
 #include "llvm/ADT/SmallVector.h"
 
 namespace clang {
+  class CXXConstructorDecl;
   class FunctionDecl;
 
   /// ImplicitConversionKind - The kind of implicit conversion used to
@@ -114,6 +115,13 @@
     /// is an opaque pointer that can be translated into a QualType.
     void *ToTypePtr;
 
+    /// CopyConstructor - The copy constructor that is used to perform
+    /// this conversion, when the conversion is actually just the
+    /// initialization of an object via copy constructor. Such
+    /// conversions are either identity conversions or derived-to-base
+    /// conversions.
+    CXXConstructorDecl *CopyConstructor;
+
     void setAsIdentityConversion();        
     ImplicitConversionRank getRank() const;
     bool isPointerConversionToBool() const;

Modified: cfe/trunk/test/SemaCXX/converting-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/converting-constructor.cpp?rev=58629&r1=58628&r2=58629&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/converting-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/converting-constructor.cpp Mon Nov  3 13:09:14 2008
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only %s 
+// RUN: clang -fsyntax-only -verify %s 
 class Z { };
 
 class Y { 
@@ -18,6 +18,6 @@
   f(s);
   f(1.0f);
   f(y);
-  f(z); // expected-error{{incompatible}}
+  f(z); // expected-error{{incompatible type passing 'class Z', expected 'class X'}}
 }
 

Modified: cfe/trunk/test/SemaCXX/overload-call-copycon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call-copycon.cpp?rev=58629&r1=58628&r2=58629&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call-copycon.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call-copycon.cpp Mon Nov  3 13:09:14 2008
@@ -36,3 +36,13 @@
   int& i1 = copycon3(b);
   float& f1 = copycon3(bc);
 }
+
+
+class C : public B { };
+
+float& copycon4(A a);
+int& copycon4(B b);
+
+void test_copycon4(C c) {
+  int& i = copycon4(c);
+};





More information about the cfe-commits mailing list