]> granicus.if.org Git - clang/commitdiff
Properly diagnose invalid casts to function references. Patch by
authorDouglas Gregor <dgregor@apple.com>
Mon, 8 Nov 2010 03:40:48 +0000 (03:40 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 8 Nov 2010 03:40:48 +0000 (03:40 +0000)
Faisal Vali, tweaked by me. Fixes PR8230.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaCXXCast.cpp
lib/Sema/SemaInit.cpp
lib/Sema/SemaOverload.cpp
test/CXX/expr/expr.unary/expr.unary.op/p4.cpp
test/CXX/over/over.over/p2.cpp
test/CXX/over/over.over/p4.cpp
test/SemaCXX/addr-of-overloaded-function.cpp
test/SemaCXX/static-cast.cpp

index 8f36ec9db085dfc574b2aeffa2f3a147d54614a6..1d025c81a31fb8d6cd3bbb3f740895b252c14baf 100644 (file)
@@ -2449,6 +2449,12 @@ def note_parameter_here : Note<
 // C++ casts
 // These messages adhere to the TryCast pattern: %0 is an int specifying the
 // cast type, %1 is the source type, %2 is the destination type.
+def err_bad_reinterpret_cast_overload : Error<
+  "reinterpret_cast cannot resolve overloaded function %0 to type %1">;
+
+def err_bad_static_cast_overload : Error<
+  "address of overloaded function %0 cannot be static_cast to type %1">;
+
 def err_bad_cxx_cast_generic : Error<
   "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
   "functional-style cast}0 from %1 to %2 is not allowed">;
index fc9ef73a590d378f3aa53eaf684181f51fa932fd..ef71599ead23d3ff5bb782dce0036cbf67f4a007 100644 (file)
@@ -21,6 +21,9 @@
 #include <set>
 using namespace clang;
 
+
+static void NoteAllOverloadCandidates(Expr* const Expr, Sema& sema);
+
 enum TryCastResult {
   TC_NotApplicable, ///< The cast method is not applicable.
   TC_Success,       ///< The cast method is appropriate and successful.
@@ -37,6 +40,9 @@ enum CastType {
   CT_Functional   ///< Type(expr)
 };
 
+
+
+
 static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
                            const SourceRange &OpRange,
                            const SourceRange &DestRange);
@@ -469,8 +475,21 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
   if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange,
                          msg, Kind)
       != TC_Success && msg != 0)
-    Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret
+  {
+    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
+      Self.Diag(OpRange.getBegin(), msg) << CT_Reinterpret
       << SrcExpr->getType() << DestType << OpRange;
+  }
+    
 }
 
 
@@ -495,8 +514,18 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
   unsigned msg = diag::err_bad_cxx_cast_generic;
   if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg,
                     Kind, BasePath) != TC_Success && msg != 0)
-    Self.Diag(OpRange.getBegin(), msg) << CT_Static
+  {
+    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
+      Self.Diag(OpRange.getBegin(), msg) << CT_Static
       << SrcExpr->getType() << DestType << OpRange;
+  }
   else if (Kind == CK_Unknown || Kind == CK_BitCast)
     Self.CheckCastAlign(SrcExpr, DestType, OpRange);
 }
@@ -964,17 +993,20 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
     }
   }
   
-  // At this point of CheckStaticCast, if the destination is a reference,
-  // this has to work. There is no other way that works.
-  // On the other hand, if we're checking a C-style cast, we've still got
-  // the reinterpret_cast way.
   InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
   InitializationKind InitKind
     = InitializationKind::CreateCast(/*FIXME:*/OpRange, 
                                                                CStyle);    
   InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1);
+
+  // At this point of CheckStaticCast, if the destination is a reference,
+  // or the expression is an overload expression this has to work. 
+  // There is no other way that works.
+  // On the other hand, if we're checking a C-style cast, we've still got
+  // the reinterpret_cast way.
+  
   if (InitSeq.getKind() == InitializationSequence::FailedSequence && 
-      (CStyle || !DestType->isReferenceType()))
+    (CStyle || !DestType->isReferenceType()))
     return TC_NotApplicable;
     
   ExprResult Result
@@ -1062,6 +1094,31 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType,
   return TC_Success;
 }
 
+
+static void NoteAllOverloadCandidates(Expr* const Expr, Sema& sema)
+{
+  
+  assert(Expr->getType() == sema.Context.OverloadTy);
+
+  OverloadExpr::FindResult Ovl = OverloadExpr::find(Expr);
+  OverloadExpr *const OvlExpr = Ovl.Expression;
+
+  for (UnresolvedSetIterator it = OvlExpr->decls_begin(),
+    end = OvlExpr->decls_end(); it != end; ++it) {
+    if ( FunctionTemplateDecl *ftd = 
+              dyn_cast<FunctionTemplateDecl>((*it)->getUnderlyingDecl()) )
+    {
+           sema.NoteOverloadCandidate(ftd->getTemplatedDecl());   
+    }
+    else if ( FunctionDecl *f = 
+                dyn_cast<FunctionDecl>((*it)->getUnderlyingDecl()) )
+    {
+      sema.NoteOverloadCandidate(f);
+    }
+  }
+}
+
+
 static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
                                         QualType DestType, bool CStyle,
                                         const SourceRange &OpRange,
@@ -1071,6 +1128,12 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
   
   DestType = Self.Context.getCanonicalType(DestType);
   QualType SrcType = SrcExpr->getType();
+
+  // Is the source an overloaded name? (i.e. &foo)
+  // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5)
+  if (SrcType == Self.Context.OverloadTy )
+    return TC_NotApplicable;
+
   if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
     bool LValue = DestTypeTmp->isLValueReferenceType();
     if (LValue && SrcExpr->isLvalue(Self.Context) != Expr::LV_Valid) {
@@ -1086,6 +1149,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
     // This code does this transformation for the checked types.
     DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
     SrcType = Self.Context.getPointerType(SrcType);
+    
     IsLValueCast = true;
   }
 
@@ -1326,8 +1390,22 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr,
   }
 
   if (tcr != TC_Success && msg != 0)
-    Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle)
-      << CastExpr->getType() << CastTy << R;
+  {
+    if (CastExpr->getType() == Context.OverloadTy)
+    {
+      DeclAccessPair Found;
+      FunctionDecl* Fn = ResolveAddressOfOverloadedFunction(CastExpr, 
+                                CastTy,
+                                /* Complain */ true,
+                                Found);
+      assert(!Fn && "cast failed but able to resolve overload expression!!");
+    }
+    else
+    {
+      Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle)
+        << CastExpr->getType() << CastTy << R;
+    }
+  }
   else if (Kind == CK_Unknown || Kind == CK_BitCast)
     CheckCastAlign(CastExpr, CastTy, R);
 
index 616b2a0bf521e7e394730d802fae8089d1b6248d..bee2ba46a8764b31c99bd290e5854cf583ad6c22 100644 (file)
@@ -3202,7 +3202,12 @@ InitializationSequence::InitializationSequence(Sema &S,
                               /*SuppressUserConversions*/ true,
                               /*AllowExplicitConversions*/ false,
                               /*InOverloadResolution*/ false))
-    SetFailed(InitializationSequence::FK_ConversionFailed);
+  {
+    if (Initializer->getType() == Context.OverloadTy )
+      SetFailed(InitializationSequence::FK_AddressOfOverloadFailed);
+    else
+      SetFailed(InitializationSequence::FK_ConversionFailed);
+  }
   else
     setSequenceKind(StandardConversion);
 }
index af0456bf361ec77712146e6aebd46aea1c19e588..3ed79fd4613c0e3749687ce1937e738760ea3f59 100644 (file)
@@ -6632,10 +6632,13 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
 
   // FIXME: We should probably return the same thing that BestViableFunction
   // returns (even if we issue the diagnostics here).
-  Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
-    << Matches[0].second->getDeclName();
-  for (unsigned I = 0, E = Matches.size(); I != E; ++I)
-    NoteOverloadCandidate(Matches[I].second);
+  if (Complain) {
+    Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous)
+      << Matches[0].second->getDeclName();
+    for (unsigned I = 0, E = Matches.size(); I != E; ++I)
+      NoteOverloadCandidate(Matches[I].second);
+  }
+
   return 0;
 }
 
index 170c734fd30796b6d22a072a787d2a25339c110f..06cc61074026a2f81d5cf54abdfe2986616f5368 100644 (file)
@@ -7,8 +7,7 @@ namespace test0 {
     template<typename T> void g(T);
 
     void test() {
-      // FIXME: this diagnostic is terrible
-      foo(&g<int>); // expected-error {{cannot initialize a parameter of type 'void (test0::A::*)(int)' with an rvalue of type '<overloaded function type>'}}
+      foo(&g<int>); // expected-error {{can't form member pointer of type 'void (test0::A::*)(int)' without '&' and class name}}
     }
   };
 }
@@ -39,7 +38,6 @@ namespace test2 {
   };
 
   void A::test() {
-    // FIXME: This diagnostic is terrible.
-    int (A::*ptr)(int) = &(A::foo); // expected-error {{cannot initialize a variable of type 'int (test2::A::*)(int)' with an rvalue of type '<overloaded function type>'}}
+    int (A::*ptr)(int) = &(A::foo); // expected-error {{can't form member pointer of type 'int (test2::A::*)(int)' without '&' and class name}}
   }
 }
index e8840d205e8784b28231c8045fac7d0778429c86..1c3d036b1538327b8a2502968cf2ce3db476f1ee 100644 (file)
@@ -5,6 +5,5 @@ template<typename T> T f0(T, T);
 void test_f0() {
   int (*f0a)(int, int) = f0;
   int (*f0b)(int, int) = &f0;
-  int (*f0c)(int, float) = f0; // expected-error{{cannot initialize}}
-  // FIXME: poor error message above!
+  int (*f0c)(int, float) = f0; // expected-error{{address of overloaded function 'f0' does not match required type 'int (int, float)'}}
 }
index 4189218f6521fde78cfdd442399c8462bd5b6d21..7b5009ab6fa6e578c85729224d506a6d67aa8ac0 100644 (file)
@@ -17,7 +17,6 @@ int f0(int);
 
 void test_f0_2() {
   using namespace N;
-  int (*fp0)(int) = f0; // expected-error{{ambiguous}} \ 
-                        // expected-error{{cannot initialize}}
+  int (*fp0)(int) = f0; // expected-error{{address of overloaded function 'f0' is ambiguous}}
   float (*fp1)(float) = f0;
 }
index ab80d8f14165c6e43fa212aa15f3e1c00e3d251c..c095e946c8b71c9cac6794abd587652526e5e766 100644 (file)
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s 
-int f(double);
-int f(int);
+int f(double); // expected-note{{candidate function}}
+int f(int); // expected-note{{candidate function}}
 
 int (*pfd)(double) = f; // selects f(double)
 int (*pfd2)(double) = &f; // selects f(double)
@@ -9,7 +9,7 @@ int (*pfi)(int) = &f;    // selects f(int)
 // FIXME: This error message is not very good. We need to keep better
 // track of what went wrong when the implicit conversion failed to
 // give a better error message here.
-int (*pfe)(...) = &f;    // expected-error{{cannot initialize a variable of type 'int (*)(...)' with an rvalue of type '<overloaded function type>'}}
+int (*pfe)(...) = &f;    // expected-error{{address of overloaded function 'f' does not match required type 'int (...)'}}
 int (&rfi)(int) = f;     // selects f(int)
 int (&rfd)(double) = f;  // selects f(double)
 
@@ -98,10 +98,10 @@ namespace PR7971 {
 }
 
 namespace PR8033 {
-  template <typename T1, typename T2> int f(T1 *, const T2 *); // expected-note{{candidate function [with T1 = const int, T2 = int]}}
-  template <typename T1, typename T2> int f(const T1 *, T2 *); // expected-note{{candidate function [with T1 = int, T2 = const int]}}
+  template <typename T1, typename T2> int f(T1 *, const T2 *); // expected-note 2{{candidate function [with T1 = const int, T2 = int]}}
+  template <typename T1, typename T2> int f(const T1 *, T2 *); // expected-note 2{{candidate function [with T1 = int, T2 = const int]}}
   int (*p)(const int *, const int *) = f; // expected-error{{address of overloaded function 'f' is ambiguous}} \
-  // expected-error{{cannot initialize a variable of type}}
+  // expected-error{{address of overloaded function 'f' is ambiguous}}
 
 }
 
index c8639a9544057d56b83ab7c4e0004f04b72b2dba..46c6eee2c4e8770ee16277a0f26325fe32e7347d 100644 (file)
@@ -184,7 +184,7 @@ void PR5897() { (void)static_cast<const int(*)[1]>((const void*)0); }
 
 namespace PR6072 {
   struct A { }; 
-  struct B : A { void f(int); void f(); }; 
+  struct B : A { void f(int); void f(); };  // expected-note 2{{candidate function}}
   struct C : B { };
   struct D { };
 
@@ -192,6 +192,6 @@ namespace PR6072 {
     (void)static_cast<void (A::*)()>(&B::f);
     (void)static_cast<void (B::*)()>(&B::f);
     (void)static_cast<void (C::*)()>(&B::f);
-    (void)static_cast<void (D::*)()>(&B::f); // expected-error{{static_cast from '<overloaded function type>' to 'void (PR6072::D::*)()' is not allowed}}
+    (void)static_cast<void (D::*)()>(&B::f); // expected-error{{address of overloaded function 'f' cannot be static_cast to type 'void (PR6072::D::*)()'}}
   }
 }