]> granicus.if.org Git - clang/commitdiff
Tweak Sema::CheckReferenceInit so that it (optionally) computes an
authorDouglas Gregor <dgregor@apple.com>
Wed, 29 Oct 2008 02:00:59 +0000 (02:00 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 29 Oct 2008 02:00:59 +0000 (02:00 +0000)
ImplicitConversionSequence and, when doing so, following the specific
rules of [over.best.ics].

The computation of the implicit conversion sequences implements C++
[over.ics.ref], but we do not (yet) have ranking for implicit
conversion sequences that use reference binding.

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

lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaOverload.h
test/SemaCXX/overload-call.cpp

index 87d7cd139f1737b84c6cfccd80216e50e6beb3e9..1cff55ea2437acf9ce985e7eb48b4a2346ef084e 100644 (file)
@@ -1139,10 +1139,11 @@ private:
     Ref_Compatible
   };
 
-  ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2);
+  ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2,
+                                                      bool& DerivedToBase);
 
   bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
-                          bool Complain = true);
+                          ImplicitConversionSequence *ICS = 0);
 
   /// CheckCastTypes - Check type constraints for casting between types.
   bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
index 7e35ff4df3a7a15c6806c6d59d35fd92f6592ee8..ef9ed9ba13dfb6d85d047e189761a66b25536712 100644 (file)
@@ -688,7 +688,8 @@ void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc,
 /// type, and the first type (T1) is the pointee type of the reference
 /// type being initialized.
 Sema::ReferenceCompareResult 
-Sema::CompareReferenceRelationship(QualType T1, QualType T2) {
+Sema::CompareReferenceRelationship(QualType T1, QualType T2, 
+                                   bool& DerivedToBase) {
   assert(!T1->isReferenceType() && "T1 must be the pointee type of the reference type");
   assert(!T2->isReferenceType() && "T2 cannot be a reference type");
 
@@ -701,10 +702,11 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2) {
   //   Given types “cv1 T1” and “cv2 T2,” “cv1 T1” is
   //   reference-related to “cv2 T2” if T1 is the same type as T2, or 
   //   T1 is a base class of T2.
-  //
-  // If neither of these conditions is met, the two types are not
-  // reference related at all.
-  if (UnqualT1 != UnqualT2 && !IsDerivedFrom(UnqualT2, UnqualT1))
+  if (UnqualT1 == UnqualT2)
+    DerivedToBase = false;
+  else if (IsDerivedFrom(UnqualT2, UnqualT1))
+    DerivedToBase = true;
+  else
     return Ref_Incompatible;
 
   // At this point, we know that T1 and T2 are reference-related (at
@@ -731,17 +733,27 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2) {
 /// list), and DeclType is the type of the declaration. When Complain
 /// is true, this routine will produce diagnostics (and return true)
 /// when the declaration cannot be initialized with the given
-/// initializer. When Complain is false, this routine will return true
-/// when the initialization cannot be performed, but will not produce
-/// any diagnostics or alter Init.
-bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
+/// initializer. When ICS is non-null, this routine will compute the
+/// implicit conversion sequence according to C++ [over.ics.ref] and
+/// will not produce any diagnostics; when ICS is null, it will emit
+/// diagnostics when any errors are found.
+bool 
+Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, 
+                         ImplicitConversionSequence *ICS) {
   assert(DeclType->isReferenceType() && "Reference init needs a reference");
 
   QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
   QualType T2 = Init->getType();
 
+  // Compute some basic properties of the types and the initializer.
+  bool DerivedToBase = false;
   Expr::isLvalueResult InitLvalue = Init->isLvalue(Context);
-  ReferenceCompareResult RefRelationship = CompareReferenceRelationship(T1, T2);
+  ReferenceCompareResult RefRelationship 
+    = CompareReferenceRelationship(T1, T2, DerivedToBase);
+
+  // Most paths end in a failed conversion.
+  if (ICS)
+    ICS->ConversionKind = ImplicitConversionSequence::BadConversion;
 
   // C++ [dcl.init.ref]p5:
   //   A reference to type “cv1 T1” is initialized by an expression
@@ -752,11 +764,37 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
   bool BindsDirectly = false;
   //       -- is an lvalue (but is not a bit-field), and “cv1 T1” is
   //          reference-compatible with “cv2 T2,” or
-  if (InitLvalue == Expr::LV_Valid && !Init->isBitField() &&
-      RefRelationship >= Ref_Compatible) {
+  //
+  // Note that the bit-field check is skipped if we are just computing
+  // the implicit conversion sequence (C++ [over.best.ics]p2).
+  if (InitLvalue == Expr::LV_Valid && (ICS || !Init->isBitField()) &&
+      RefRelationship >= Ref_Compatible_With_Added_Qualification) {
     BindsDirectly = true;
 
-    if (!Complain) {
+    if (ICS) {
+      // C++ [over.ics.ref]p1:
+      //   When a parameter of reference type binds directly (8.5.3)
+      //   to an argument expression, the implicit conversion sequence
+      //   is the identity conversion, unless the argument expression
+      //   has a type that is a derived class of the parameter type,
+      //   in which case the implicit conversion sequence is a
+      //   derived-to-base Conversion (13.3.3.1).
+      ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+      ICS->Standard.First = ICK_Identity;
+      ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+      ICS->Standard.Third = ICK_Identity;
+      ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
+      ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+      ICS->ReferenceBinding = true;
+      ICS->DirectBinding = true;
+
+      // Nothing more to do: the inaccessibility/ambiguity check for
+      // derived-to-base conversions is suppressed when we're
+      // computing the implicit conversion sequence (C++
+      // [over.best.ics]p2).
+      return false;
+    } else {
+      // Perform the conversion.
       // FIXME: Binding to a subobject of the lvalue is going to require
       // more AST annotation than this.
       ImpCastExprToType(Init, T1);    
@@ -770,7 +808,7 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
   //          applicable conversion functions (13.3.1.6) and choosing
   //          the best one through overload resolution (13.3)),
   // FIXME: Implement this second bullet, once we have conversion
-  //        functions.
+  //        functions. Also remember C++ [over.ics.ref]p1, second part.
 
   if (BindsDirectly) {
     // C++ [dcl.init.ref]p4:
@@ -785,20 +823,18 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
     // complain about errors, because we should not be checking for
     // ambiguity (or inaccessibility) unless the reference binding
     // actually happens.
-    if (Complain && 
-        (Context.getCanonicalType(T1).getUnqualifiedType() 
-           != Context.getCanonicalType(T2).getUnqualifiedType()) && 
-        CheckDerivedToBaseConversion(T2, T1, Init->getSourceRange().getBegin(),
-                                     Init->getSourceRange()))
-      return true;
-          
-    return false;
+    if (DerivedToBase) 
+      return CheckDerivedToBaseConversion(T2, T1, 
+                                          Init->getSourceRange().getBegin(),
+                                          Init->getSourceRange());
+    else
+      return false;
   }
 
   //     -- Otherwise, the reference shall be to a non-volatile const
   //        type (i.e., cv1 shall be const).
   if (T1.getCVRQualifiers() != QualType::Const) {
-    if (Complain)
+    if (!ICS)
       Diag(Init->getSourceRange().getBegin(),
            diag::err_not_reference_to_const_init,
            T1.getAsString(), 
@@ -832,8 +868,17 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
   // a temporary in this case. FIXME: We will, however, have to check
   // for the presence of a copy constructor in C++98/03 mode.
   if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
-      RefRelationship >= Ref_Compatible) {
-    if (!Complain) {
+      RefRelationship >= Ref_Compatible_With_Added_Qualification) {
+    if (ICS) {
+      ICS->ConversionKind = ImplicitConversionSequence::StandardConversion;
+      ICS->Standard.First = ICK_Identity;
+      ICS->Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity;
+      ICS->Standard.Third = ICK_Identity;
+      ICS->Standard.FromTypePtr = T2.getAsOpaquePtr();
+      ICS->Standard.ToTypePtr = T1.getAsOpaquePtr();
+      ICS->ReferenceBinding = true;
+      ICS->DirectBinding = false;      
+    } else {
       // FIXME: Binding to a subobject of the rvalue is going to require
       // more AST annotation than this.
       ImpCastExprToType(Init, T1);
@@ -853,7 +898,7 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
     // we would be reference-compatible or reference-compatible with
     // added qualification. But that wasn't the case, so the reference
     // initialization fails.
-    if (Complain)
+    if (!ICS)
       Diag(Init->getSourceRange().getBegin(),
            diag::err_reference_init_drops_quals,
            T1.getAsString(), 
@@ -863,9 +908,21 @@ bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
   }
 
   // Actually try to convert the initializer to T1.
-  if (Complain)
+  if (ICS) {
+    /// C++ [over.ics.ref]p2:
+    /// 
+    ///   When a parameter of reference type is not bound directly to
+    ///   an argument expression, the conversion sequence is the one
+    ///   required to convert the argument expression to the
+    ///   underlying type of the reference according to
+    ///   13.3.3.1. Conceptually, this conversion sequence corresponds
+    ///   to copy-initializing a temporary of the underlying type with
+    ///   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);
+    return ICS->ConversionKind == ImplicitConversionSequence::BadConversion;
+  } else {
     return PerformImplicitConversion(Init, T1);
-  else
-    return (TryImplicitConversion(Init, T1).ConversionKind
-              == ImplicitConversionSequence::BadConversion);
+  }
 }
index 831765376b6a0f91a7f91adf30b3d54cafecc940..b23db4876775d5eb6db8bbcf6f9fdc662c823736 100644 (file)
@@ -1123,7 +1123,7 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
                 Fn->getSourceRange());
   
   // We know the result type of the call, set it.
-  TheCall->setType(FuncT->getResultType());
+  TheCall->setType(FuncT->getResultType().getNonReferenceType());
     
   if (const FunctionTypeProto *Proto = dyn_cast<FunctionTypeProto>(FuncT)) {
     // C99 6.5.2.2p7 - the arguments are implicitly converted, as if by 
index 8e765485b11e8b0c12f3adc54e37fdcb5365e309..551f61a56e8bdb549b9fa5c31d0854f06b31d524 100644 (file)
@@ -39,6 +39,7 @@ GetConversionCategory(ImplicitConversionKind Kind) {
     ICC_Conversion,
     ICC_Conversion,
     ICC_Conversion,
+    ICC_Conversion,
     ICC_Conversion
   };
   return Category[(int)Kind];
@@ -61,6 +62,7 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) {
     ICR_Conversion,
     ICR_Conversion,
     ICR_Conversion,
+    ICR_Conversion,
     ICR_Conversion
   };
   return Rank[(int)Kind];
@@ -82,7 +84,8 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) {
     "Floating-integral conversion",
     "Pointer conversion",
     "Pointer-to-member conversion",
-    "Boolean conversion"
+    "Boolean conversion",
+    "Derived-to-base conversion"
   };
   return Name[Kind];
 }
@@ -1066,10 +1069,7 @@ Sema::TryCopyInitialization(Expr *From, QualType ToType) {
     return ICS;
   } else if (ToType->isReferenceType()) {
     ImplicitConversionSequence ICS;
-    if (CheckReferenceInit(From, ToType, /*Complain=*/false))
-      ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
-    else
-      ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+    CheckReferenceInit(From, ToType, &ICS);
     return ICS;
   } else {
     return TryImplicitConversion(From, ToType);
index 27190f6e9966c9494275bdc78a6289e8d1a9bed1..558718c0d94dcb2be1dd03e57050268fcdde5dbd 100644 (file)
@@ -38,6 +38,7 @@ namespace clang {
     ICK_Pointer_Conversion,  ///< Pointer conversions (C++ 4.10)
     ICK_Pointer_Member,      ///< Pointer-to-member conversions (C++ 4.11)
     ICK_Boolean_Conversion,  ///< Boolean conversions (C++ 4.12)
+    ICK_Derived_To_Base,     ///< Derived-to-base (C++ [over.best.ics][)
     ICK_Num_Conversion_Kinds ///< The number of conversion kinds
   };
 
@@ -91,9 +92,9 @@ namespace clang {
     /// Third - The third conversion can be a qualification conversion.
     ImplicitConversionKind Third : 8;
 
-    /// Deprecated - Whether this is a deprecated conversion, such as
-    /// converting a string literal to a pointer to non-const
-    /// character data (C++ 4.2p2).
+    /// Deprecated - Whether this the deprecated conversion of a
+    /// string literal to a pointer to non-const character data 
+    /// (C++ 4.2p2).
     bool Deprecated : 1;
 
     /// FromType - The type that this conversion is converting
@@ -154,7 +155,17 @@ namespace clang {
     };
 
     /// ConversionKind - The kind of implicit conversion sequence.
-    Kind ConversionKind;
+    /// As usual, we use "unsigned" here because VC++ makes enum bitfields
+    /// signed.
+    unsigned ConversionKind : 2;
+
+    /// ReferenceBinding - True when this is a reference binding 
+    /// (C++ [over.ics.ref]).
+    bool ReferenceBinding : 1;
+
+    /// DirectBinding - True when this is a reference binding that is a 
+    /// direct binding (C++ [dcl.init.ref]).
+    bool DirectBinding : 1;
 
     union {
       /// When ConversionKind == StandardConversion, provides the
index 663474d32829a9fc4f8676f9eb2df5fbecff6391..81e437a72f7dfc23999a2d00b750faa5e1412e8e 100644 (file)
@@ -225,3 +225,31 @@ void intref_test() {
   float* ir1 = intref(5);
   float* ir2 = intref(5.5);
 }
+
+// Test reference binding vs. standard conversions.
+int& bind_vs_conv(const double&);
+float& bind_vs_conv(int);
+
+void bind_vs_conv_test()
+{
+  int& i1 = bind_vs_conv(1.0f);
+  float& f1 = bind_vs_conv((short)1);
+}
+
+// Test that cv-qualifiers get subsumed in the reference binding.
+struct X { };
+struct Y { };
+struct Z : X, Y { };
+
+int& cvqual_subsume(X&); // expected-note{{candidate function}}
+float& cvqual_subsume(const Y&); // expected-note{{candidate function}}
+
+int& cvqual_subsume2(const X&);
+float& cvqual_subsume2(const volatile Y&);
+
+Z get_Z();
+
+void cvqual_subsume_test(Z z) {
+  cvqual_subsume(z); // expected-error{{call to 'cvqual_subsume' is ambiguous; candidates are:}}
+  int& x = cvqual_subsume2(get_Z()); // okay: only binds to the first one
+}