From: Douglas Gregor Date: Mon, 8 Nov 2010 03:40:48 +0000 (+0000) Subject: Properly diagnose invalid casts to function references. Patch by X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8e960435696b4ccf6a8ad0ed0530e3280b77af8b;p=clang Properly diagnose invalid casts to function references. Patch by Faisal Vali, tweaked by me. Fixes PR8230. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118400 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8f36ec9db0..1d025c81a3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index fc9ef73a59..ef71599ead 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -21,6 +21,9 @@ #include 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; 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((*it)->getUnderlyingDecl()) ) + { + sema.NoteOverloadCandidate(ftd->getTemplatedDecl()); + } + else if ( FunctionDecl *f = + dyn_cast((*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()) { 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); diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 616b2a0bf5..bee2ba46a8 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -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); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index af0456bf36..3ed79fd461 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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; } diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp index 170c734fd3..06cc610740 100644 --- a/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp +++ b/test/CXX/expr/expr.unary/expr.unary.op/p4.cpp @@ -7,8 +7,7 @@ namespace test0 { template void g(T); void test() { - // FIXME: this diagnostic is terrible - foo(&g); // expected-error {{cannot initialize a parameter of type 'void (test0::A::*)(int)' with an rvalue of type ''}} + foo(&g); // 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 ''}} + int (A::*ptr)(int) = &(A::foo); // expected-error {{can't form member pointer of type 'int (test2::A::*)(int)' without '&' and class name}} } } diff --git a/test/CXX/over/over.over/p2.cpp b/test/CXX/over/over.over/p2.cpp index e8840d205e..1c3d036b15 100644 --- a/test/CXX/over/over.over/p2.cpp +++ b/test/CXX/over/over.over/p2.cpp @@ -5,6 +5,5 @@ template 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)'}} } diff --git a/test/CXX/over/over.over/p4.cpp b/test/CXX/over/over.over/p4.cpp index 4189218f65..7b5009ab6f 100644 --- a/test/CXX/over/over.over/p4.cpp +++ b/test/CXX/over/over.over/p4.cpp @@ -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; } diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp index ab80d8f141..c095e946c8 100644 --- a/test/SemaCXX/addr-of-overloaded-function.cpp +++ b/test/SemaCXX/addr-of-overloaded-function.cpp @@ -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 ''}} +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 int f(T1 *, const T2 *); // expected-note{{candidate function [with T1 = const int, T2 = int]}} - template int f(const T1 *, T2 *); // expected-note{{candidate function [with T1 = int, T2 = const int]}} + template int f(T1 *, const T2 *); // expected-note 2{{candidate function [with T1 = const int, T2 = int]}} + template 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}} } diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp index c8639a9544..46c6eee2c4 100644 --- a/test/SemaCXX/static-cast.cpp +++ b/test/SemaCXX/static-cast.cpp @@ -184,7 +184,7 @@ void PR5897() { (void)static_cast((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(&B::f); (void)static_cast(&B::f); (void)static_cast(&B::f); - (void)static_cast(&B::f); // expected-error{{static_cast from '' to 'void (PR6072::D::*)()' is not allowed}} + (void)static_cast(&B::f); // expected-error{{address of overloaded function 'f' cannot be static_cast to type 'void (PR6072::D::*)()'}} } }