[cfe-commits] r125506 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Initialization.h lib/Sema/SemaCXXCast.cpp test/CXX/special/class.copy/p9.cpp test/SemaCXX/cast-conversion.cpp test/SemaCXX/vector-casts.cpp test/SemaObjCXX/cstyle-cast.mm test/SemaTemplate/instantiate-cast.cpp

John McCall rjmccall at apple.com
Mon Feb 14 10:34:10 PST 2011


Author: rjmccall
Date: Mon Feb 14 12:34:10 2011
New Revision: 125506

URL: http://llvm.org/viewvc/llvm-project?rev=125506&view=rev
Log:
Provide overload diagnostics when explicit casts involving class types fail.
PR8626.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/lib/Sema/SemaCXXCast.cpp
    cfe/trunk/test/CXX/special/class.copy/p9.cpp
    cfe/trunk/test/SemaCXX/cast-conversion.cpp
    cfe/trunk/test/SemaCXX/vector-casts.cpp
    cfe/trunk/test/SemaObjCXX/cstyle-cast.mm
    cfe/trunk/test/SemaTemplate/instantiate-cast.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Feb 14 12:34:10 2011
@@ -1414,6 +1414,17 @@
     "built-in candidate %0">;
 def err_ovl_no_viable_function_in_init : Error<
   "no matching constructor for initialization of %0">;
+def err_ovl_no_conversion_in_cast : Error<
+  "cannot convert %1 to %2 without a conversion operator">;
+def err_ovl_no_viable_conversion_in_cast : Error<
+  "no matching conversion for %select{|static_cast|reinterpret_cast|"
+  "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">;
+def err_ovl_ambiguous_conversion_in_cast : Error<
+  "ambiguous conversion for %select{|static_cast|reinterpret_cast|"
+  "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">;
+def err_ovl_deleted_conversion_in_cast : Error<
+  "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
+  "functional-style cast}0 from %1 to %2 uses deleted function">;
 def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">;
 def err_ref_init_ambiguous : Error<
   "reference initialization of type %0 with initializer of type %1 is ambiguous">;

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Mon Feb 14 12:34:10 2011
@@ -791,12 +791,18 @@
     return FailedCandidateSet;
   }
 
+  /// brief Get the overloading result, for when the initialization
+  /// sequence failed due to a bad overload.
+  OverloadingResult getFailedOverloadResult() const {
+    return FailedOverloadResult;
+  }
+
   /// \brief Determine why initialization failed.
   FailureKind getFailureKind() const {
     assert(getKind() == FailedSequence && "Not an initialization failure!");
     return Failure;
   }
-  
+
   /// \brief Dump a representation of this initialization sequence to 
   /// the given stream, for debugging purposes.
   void dump(llvm::raw_ostream &OS) const;

Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Mon Feb 14 12:34:10 2011
@@ -214,6 +214,92 @@
   return ExprError();
 }
 
+/// Try to diagnose a failed overloaded cast.  Returns true if
+/// diagnostics were emitted.
+static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT,
+                                      SourceRange range, Expr *src,
+                                      QualType destType) {
+  switch (CT) {
+  // These cast kinds don't consider user-defined conversions.
+  case CT_Const:
+  case CT_Reinterpret:
+  case CT_Dynamic:
+    return false;
+
+  // These do.
+  case CT_Static:
+  case CT_CStyle:
+  case CT_Functional:
+    break;
+  }
+
+  QualType srcType = src->getType();
+  if (!destType->isRecordType() && !srcType->isRecordType())
+    return false;
+
+  InitializedEntity entity = InitializedEntity::InitializeTemporary(destType);
+  InitializationKind initKind
+    = InitializationKind::CreateCast(/*type range?*/ range,
+                                     (CT == CT_CStyle || CT == CT_Functional));
+  InitializationSequence sequence(S, entity, initKind, &src, 1);
+
+  assert(sequence.getKind() == InitializationSequence::FailedSequence &&
+         "initialization succeeded on second try?");
+  switch (sequence.getFailureKind()) {
+  default: return false;
+
+  case InitializationSequence::FK_ConstructorOverloadFailed:
+  case InitializationSequence::FK_UserConversionOverloadFailed:
+    break;
+  }
+
+  OverloadCandidateSet &candidates = sequence.getFailedCandidateSet();
+
+  unsigned msg = 0;
+  OverloadCandidateDisplayKind howManyCandidates = OCD_AllCandidates;
+
+  switch (sequence.getFailedOverloadResult()) {
+  case OR_Success: llvm_unreachable("successful failed overload");
+    return false;
+  case OR_No_Viable_Function:
+    if (candidates.empty())
+      msg = diag::err_ovl_no_conversion_in_cast;
+    else
+      msg = diag::err_ovl_no_viable_conversion_in_cast;
+    howManyCandidates = OCD_AllCandidates;
+    break;
+
+  case OR_Ambiguous:
+    msg = diag::err_ovl_ambiguous_conversion_in_cast;
+    howManyCandidates = OCD_ViableCandidates;
+    break;
+
+  case OR_Deleted:
+    msg = diag::err_ovl_deleted_conversion_in_cast;
+    howManyCandidates = OCD_ViableCandidates;
+    break;
+  }
+
+  S.Diag(range.getBegin(), msg)
+    << CT << srcType << destType
+    << range << src->getSourceRange();
+
+  candidates.NoteCandidates(S, howManyCandidates, &src, 1);
+
+  return true;
+}
+
+/// Diagnose a failed cast.
+static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
+                            SourceRange opRange, Expr *src, QualType destType) {
+  if (msg == diag::err_bad_cxx_cast_generic &&
+      tryDiagnoseOverloadedCast(S, castType, opRange, src, destType))
+    return;
+
+  S.Diag(opRange.getBegin(), msg) << castType
+    << src->getType() << destType << opRange << src->getSourceRange();
+}
+
 /// UnwrapDissimilarPointerTypes - Like Sema::UnwrapSimilarPointerTypes,
 /// this removes one level of indirection from both types, provided that they're
 /// the same kind of pointer (plain or to-member). Unlike the Sema function,
@@ -492,20 +578,17 @@
                          msg, Kind)
       != TC_Success && msg != 0)
   {
-    if (SrcExpr->getType() == Self.Context.OverloadTy)
-    {
+    if (SrcExpr->getType() == Self.Context.OverloadTy) {
       //FIXME: &f<int>; is overloaded and resolvable 
       Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload) 
         << OverloadExpr::find(SrcExpr).Expression->getName()
         << DestType << OpRange;
       NoteAllOverloadCandidates(SrcExpr, Self);
 
+    } else {
+      diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType);
     }
-    else
-      Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret
-      << SrcExpr->getType() << DestType << OpRange;
-  }
-    
+  }    
 }
 
 
@@ -533,16 +616,14 @@
   if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
                     Kind, BasePath) != TC_Success && msg != 0)
   {
-    if (SrcExpr->getType() == Self.Context.OverloadTy)
-    {
+    if (SrcExpr->getType() == Self.Context.OverloadTy) {
       OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression;
       Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload)
         << oe->getName() << DestType << OpRange << oe->getQualifierRange();
       NoteAllOverloadCandidates(SrcExpr, Self);
+    } else {
+      diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType);
     }
-    else
-      Self.Diag(OpRange.getBegin(), msg) << CT_Static
-      << SrcExpr->getType() << DestType << OpRange;
   }
   else if (Kind == CK_BitCast)
     Self.CheckCastAlign(SrcExpr, DestType, OpRange);
@@ -1374,7 +1455,7 @@
   // So we finish by allowing everything that remains - it's got to be two
   // object pointers.
   return TC_Success;
-}
+}                                     
 
 bool 
 Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK,
@@ -1445,9 +1526,10 @@
                                 Found);
       assert(!Fn && "cast failed but able to resolve overload expression!!");
       (void)Fn;
+
     } else {
-      Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle)
-        << CastExpr->getType() << CastTy << R;
+      diagnoseBadCast(*this, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
+                      R, CastExpr, CastTy);
     }
   }
   else if (Kind == CK_BitCast)

Modified: cfe/trunk/test/CXX/special/class.copy/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p9.cpp?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.copy/p9.cpp (original)
+++ cfe/trunk/test/CXX/special/class.copy/p9.cpp Mon Feb 14 12:34:10 2011
@@ -15,30 +15,30 @@
   VirtualInheritsNonConstCopy(const VirtualInheritsNonConstCopy&);
 };
 
-struct ImplicitNonConstCopy1 : NonConstCopy { 
-  ImplicitNonConstCopy1();
+struct ImplicitNonConstCopy1 : NonConstCopy { // expected-note {{candidate constructor}}
+  ImplicitNonConstCopy1(); // expected-note {{candidate constructor}}
 };
 
-struct ImplicitNonConstCopy2 {
-  ImplicitNonConstCopy2();
+struct ImplicitNonConstCopy2 { // expected-note {{candidate constructor}}
+  ImplicitNonConstCopy2(); // expected-note {{candidate constructor}}
   NonConstCopy ncc;
 };
 
-struct ImplicitNonConstCopy3 { 
-  ImplicitNonConstCopy3();
+struct ImplicitNonConstCopy3 { // expected-note {{candidate constructor}}
+  ImplicitNonConstCopy3(); // expected-note {{candidate constructor}}
   NonConstCopy ncc_array[2][3];
 };
 
-struct ImplicitNonConstCopy4 : VirtualInheritsNonConstCopy { 
-  ImplicitNonConstCopy4();
+struct ImplicitNonConstCopy4 : VirtualInheritsNonConstCopy { // expected-note {{candidate constructor}}
+  ImplicitNonConstCopy4(); // expected-note {{candidate constructor}}
 };
 
 void test_non_const_copy(const ImplicitNonConstCopy1 &cincc1,
                          const ImplicitNonConstCopy2 &cincc2,
                          const ImplicitNonConstCopy3 &cincc3,
                          const ImplicitNonConstCopy4 &cincc4) {
-  (void)sizeof(ImplicitNonConstCopy1(cincc1)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy1' to 'ImplicitNonConstCopy1' is not allowed}}
-  (void)sizeof(ImplicitNonConstCopy2(cincc2)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy2' to 'ImplicitNonConstCopy2' is not allowed}}
-  (void)sizeof(ImplicitNonConstCopy3(cincc3)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy3' to 'ImplicitNonConstCopy3' is not allowed}}
-  (void)sizeof(ImplicitNonConstCopy4(cincc4)); // expected-error{{functional-style cast from 'const ImplicitNonConstCopy4' to 'ImplicitNonConstCopy4' is not allowed}}
+  (void)sizeof(ImplicitNonConstCopy1(cincc1)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy1' to 'ImplicitNonConstCopy1'}}
+  (void)sizeof(ImplicitNonConstCopy2(cincc2)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy2' to 'ImplicitNonConstCopy2'}}
+  (void)sizeof(ImplicitNonConstCopy3(cincc3)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy3' to 'ImplicitNonConstCopy3'}}
+  (void)sizeof(ImplicitNonConstCopy4(cincc4)); // expected-error{{no matching conversion for functional-style cast from 'const ImplicitNonConstCopy4' to 'ImplicitNonConstCopy4'}}
 }

Modified: cfe/trunk/test/SemaCXX/cast-conversion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cast-conversion.cpp?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cast-conversion.cpp (original)
+++ cfe/trunk/test/SemaCXX/cast-conversion.cpp Mon Feb 14 12:34:10 2011
@@ -8,14 +8,14 @@
   A(R);
 };
 
-struct B {
-  B(A);
+struct B { // expected-note 3 {{candidate constructor (the implicit copy constructor) not viable}}
+  B(A); // expected-note 3 {{candidate constructor not viable}}
 };
 
 int main () {
-  B(10);	// expected-error {{functional-style cast from 'int' to 'B' is not allowed}}
-  (B)10;	// expected-error {{C-style cast from 'int' to 'B' is not allowed}}
-  static_cast<B>(10);	// expected-error {{static_cast from 'int' to 'B' is not allowed}} \\
+  B(10);	// expected-error {{no matching conversion for functional-style cast from 'int' to 'B'}}
+  (B)10;	// expected-error {{no matching conversion for C-style cast from 'int' to 'B'}}
+  static_cast<B>(10);	// expected-error {{no matching conversion for static_cast from 'int' to 'B'}} \\
 			// expected-warning {{expression result unused}}
 }
 

Modified: cfe/trunk/test/SemaCXX/vector-casts.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/vector-casts.cpp?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/vector-casts.cpp (original)
+++ cfe/trunk/test/SemaCXX/vector-casts.cpp Mon Feb 14 12:34:10 2011
@@ -3,7 +3,7 @@
 typedef short __v4hi __attribute__((__vector_size__(8)));
 typedef short __v8hi __attribute__((__vector_size__(16)));
 
-struct S { };
+struct S { }; // expected-note 2 {{candidate constructor}}
 
 void f() {
   __v2si v2si;
@@ -23,9 +23,9 @@
   (void)(__v2si)(ll);
 
   (void)reinterpret_cast<S>(v2si); // expected-error {{reinterpret_cast from '__v2si' to 'S' is not allowed}}
-  (void)(S)v2si; // expected-error {{C-style cast from '__v2si' to 'S' is not allowed}}
+  (void)(S)v2si; // expected-error {{no matching conversion for C-style cast from '__v2si' to 'S'}}
   (void)reinterpret_cast<__v2si>(s); // expected-error {{reinterpret_cast from 'S' to '__v2si' is not allowed}}
-  (void)(__v2si)s; // expected-error {{C-style cast from 'S' to '__v2si' is not allowed}}
+  (void)(__v2si)s; // expected-error {{cannot convert 'S' to '__v2si' without a conversion operator}}
   
   (void)reinterpret_cast<unsigned char>(v2si); // expected-error {{reinterpret_cast from vector '__v2si' to scalar 'unsigned char' of different size}}
   (void)(unsigned char)v2si; // expected-error {{C-style cast from vector '__v2si' to scalar 'unsigned char' of different size}}

Modified: cfe/trunk/test/SemaObjCXX/cstyle-cast.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/cstyle-cast.mm?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/cstyle-cast.mm (original)
+++ cfe/trunk/test/SemaObjCXX/cstyle-cast.mm Mon Feb 14 12:34:10 2011
@@ -18,7 +18,7 @@
 
   I<P> *ip = (I<P>*)cft;
 
-  (id)x; // expected-error {{C-style cast from 'X' to 'id' is not allowed}}
+  (id)x; // expected-error {{cannot convert 'X' to 'id' without a conversion operator}}
 
   id *pid = (id*)ccct;
 

Modified: cfe/trunk/test/SemaTemplate/instantiate-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-cast.cpp?rev=125506&r1=125505&r2=125506&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-cast.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-cast.cpp Mon Feb 14 12:34:10 2011
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-struct A { int x; }; 
+struct A { int x; }; // expected-note 2 {{candidate constructor}}
 
 class Base { 
 public:
@@ -23,7 +23,7 @@
 template<typename T, typename U>
 struct CStyleCast0 {
   void f(T t) {
-    (void)((U)t); // expected-error{{C-style cast from 'A' to 'int' is not allowed}}
+    (void)((U)t); // expected-error{{cannot convert 'A' to 'int' without a conversion operator}}
   }
 };
 
@@ -36,7 +36,7 @@
 template<typename T, typename U>
 struct StaticCast0 {
   void f(T t) {
-    (void)static_cast<U>(t); // expected-error{{static_cast from 'int' to 'A' is not allowed}}
+    (void)static_cast<U>(t); // expected-error{{no matching conversion for static_cast from 'int' to 'A'}}
   }
 };
 
@@ -89,7 +89,7 @@
 template<typename T, typename U>
 struct FunctionalCast1 {
   void f(T t) {
-    (void)U(t); // expected-error{{functional-style cast from 'A' to 'int' is not allowed}}
+    (void)U(t); // expected-error{{cannot convert 'A' to 'int' without a conversion operator}}
   }
 };
 





More information about the cfe-commits mailing list