diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8306eb490f..d72faac338 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2686,6 +2686,10 @@ def err_bad_reinterpret_cast_overload : Error< def err_bad_static_cast_overload : Error< "address of overloaded function %0 cannot be static_cast to type %1">; +def err_bad_cstyle_cast_overload : Error< + "address of overloaded function %0 cannot be 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/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a835bb219e..c95ce62eec 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1247,12 +1247,28 @@ public: OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); + // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate(FunctionDecl *Fn); + + // Emit as a series of 'note's all template and non-templates + // identified by the expression Expr + void NoteAllOverloadCandidates(Expr* E); + + // [PossiblyAFunctionType] --> [Return] + // NonFunctionType --> NonFunctionType + // R (A) --> R(A) + // R (*)(A) --> R (A) + // R (&)(A) --> R (A) + // R (S::*)(A) --> R (A) + QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); - FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, + FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, bool Complain, DeclAccessPair &Found); - FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); + + FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From, + bool Complain = false, + DeclAccessPair* Found = 0); Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, @@ -3702,7 +3718,8 @@ public: SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag); + const PartialDiagnostic &CandidateDiag, + bool Complain = true); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 30bb5763f2..4e5a481f8d 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -22,7 +22,6 @@ using namespace clang; -static void NoteAllOverloadCandidates(Expr* const Expr, Sema& sema); enum TryCastResult { TC_NotApplicable, ///< The cast method is not applicable. @@ -122,12 +121,24 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, CXXCastPath &BasePath); static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, unsigned &msg); -static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, +static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastKind &Kind); + +static ExprResult +ResolveAndFixSingleFunctionTemplateSpecialization( + Sema &Self, Expr *SrcExpr, + bool DoFunctionPointerConverion = false, + bool Complain = false, + const SourceRange& OpRangeForComplaining = SourceRange(), + QualType DestTypeForComplaining = QualType(), + unsigned DiagIDForComplaining = 0); + + + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, @@ -583,7 +594,7 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload) << OverloadExpr::find(SrcExpr).Expression->getName() << DestType << OpRange; - NoteAllOverloadCandidates(SrcExpr, Self); + Self.NoteAllOverloadCandidates(SrcExpr); } else { diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType); @@ -604,7 +615,20 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { Self.IgnoredValueConversions(SrcExpr); - Kind = CK_ToVoid; + if (SrcExpr->getType() == Self.Context.OverloadTy) { + ExprResult SingleFunctionExpression = + ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + false, // Decay Function to ptr + true, // Complain + OpRange, DestType, diag::err_bad_static_cast_overload); + if (SingleFunctionExpression.isUsable()) + { + SrcExpr = SingleFunctionExpression.release(); + Kind = CK_ToVoid; + } + } + else + Kind = CK_ToVoid; return; } @@ -614,13 +638,12 @@ 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) - { + Kind, BasePath) != TC_Success && msg != 0) { 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); + Self.NoteAllOverloadCandidates(SrcExpr); } else { diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType); } @@ -1236,32 +1259,44 @@ 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); - } +// A helper function to resolve and fix an overloaded expression that +// can be resolved because it identifies a single function +// template specialization +// Last three arguments should only be supplied if Complain = true +static ExprResult ResolveAndFixSingleFunctionTemplateSpecialization( + Sema &Self, Expr *SrcExpr, + bool DoFunctionPointerConverion, + bool Complain, + const SourceRange& OpRangeForComplaining, + QualType DestTypeForComplaining, + unsigned DiagIDForComplaining) { + assert(SrcExpr->getType() == Self.Context.OverloadTy); + DeclAccessPair Found; + bool ret = false; + Expr* SingleFunctionExpression = 0; + if (FunctionDecl* Fn = Self.ResolveSingleFunctionTemplateSpecialization( + SrcExpr, false, // false -> Complain + &Found)) { + if (!Self.DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) { + // mark the expression as resolved to Fn + SingleFunctionExpression = Self.FixOverloadedFunctionReference(SrcExpr, + Found, Fn); + + if (DoFunctionPointerConverion) + Self.DefaultFunctionArrayLvalueConversion(SingleFunctionExpression); + } } + if (!SingleFunctionExpression && Complain) { + OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression; + Self.Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining) + << oe->getName() << DestTypeForComplaining << OpRangeForComplaining + << oe->getQualifierRange(); + Self.NoteAllOverloadCandidates(SrcExpr); + } + return SingleFunctionExpression; } - -static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, +static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, @@ -1272,9 +1307,20 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, 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 so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ... + if (SrcType == Self.Context.OverloadTy) { + // ... unless foo resolves to an lvalue unambiguously + ExprResult SingleFunctionExpr = + ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr + ); + if (SingleFunctionExpr.isUsable()) { + SrcExpr = SingleFunctionExpr.release(); + SrcType = SrcExpr->getType(); + } + else + return TC_NotApplicable; + } if (const ReferenceType *DestTypeTmp = DestType->getAs()) { bool LValue = DestTypeTmp->isLValueReferenceType(); @@ -1495,8 +1541,24 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (CastTy->isVoidType()) { IgnoredValueConversions(CastExpr); - Kind = CK_ToVoid; - return false; + bool ret = false; // false is 'able to convert' + if (CastExpr->getType() == Context.OverloadTy) { + ExprResult SingleFunctionExpr = + ResolveAndFixSingleFunctionTemplateSpecialization(*this, + CastExpr, + /* Decay Function to ptr */ false, + /* Complain */ true, + R, CastTy, diag::err_bad_cstyle_cast_overload); + if (SingleFunctionExpr.isUsable()) { + CastExpr = SingleFunctionExpr.release(); + Kind = CK_ToVoid; + } + else + ret = true; + } + else + Kind = CK_ToVoid; + return ret; } // Make sure we determine the value kind before we bail out for @@ -1547,7 +1609,9 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, CastTy, /* Complain */ true, Found); - assert(!Fn && "cast failed but able to resolve overload expression!!"); + + assert(!Fn + && "cast failed but able to resolve overload expression!!"); (void)Fn; } else { diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 3aeb518827..b0749484f5 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -3190,7 +3190,10 @@ InitializationSequence::InitializationSequence(Sema &S, /*InOverloadResolution*/ false, /*CStyle=*/Kind.isCStyleOrFunctionalCast())) { - if (Initializer->getType() == Context.OverloadTy) + DeclAccessPair dap; + if (Initializer->getType() == Context.OverloadTy && + !S.ResolveAddressOfOverloadedFunction(Initializer + , DestType, false, dap)) SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); else SetFailed(InitializationSequence::FK_ConversionFailed); @@ -4161,15 +4164,16 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); break; - case FK_ConversionFailed: + case FK_ConversionFailed: { + QualType FromType = Args[0]->getType(); S.Diag(Kind.getLocation(), diag::err_init_conversion_failed) << (int)Entity.getKind() << DestType << Args[0]->isLValue() - << Args[0]->getType() + << FromType << Args[0]->getSourceRange(); break; - + } case FK_TooManyInitsForScalar: { SourceRange R; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 3d0608ea71..6fb789cfd8 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1036,6 +1036,21 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // We were able to resolve the address of the overloaded function, // so we can convert to the type of that function. FromType = Fn->getType(); + + // we can sometimes resolve &foo regardless of ToType, so check + // if the type matches (identity) or we are converting to bool + if (!S.Context.hasSameUnqualifiedType( + S.ExtractUnqualifiedFunctionType(ToType), FromType)) { + QualType resultTy; + // if the function type matches except for [[noreturn]], it's ok + if (!IsNoReturnConversion(S.Context, FromType, + S.ExtractUnqualifiedFunctionType(ToType), resultTy)) + // otherwise, only a boolean conversion is standard + if (!ToType->isBooleanType()) + return false; + + } + if (CXXMethodDecl *Method = dyn_cast(Fn)) { if (!Method->isStatic()) { const Type *ClassType @@ -6349,6 +6364,27 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { MaybeEmitInheritedConstructorNote(*this, Fn); } +//Notes the location of all overload candidates designated through +// OverloadedExpr +void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr) { + assert(OverloadedExpr->getType() == Context.OverloadTy); + + OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr); + OverloadExpr *OvlExpr = Ovl.Expression; + + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + IEnd = OvlExpr->decls_end(); + I != IEnd; ++I) { + if (FunctionTemplateDecl *FunTmpl = + dyn_cast((*I)->getUnderlyingDecl()) ) { + NoteOverloadCandidate(FunTmpl->getTemplatedDecl()); + } else if (FunctionDecl *Fun + = dyn_cast((*I)->getUnderlyingDecl()) ) { + NoteOverloadCandidate(Fun); + } + } +} + /// Diagnoses an ambiguous conversion. The partial diagnostic is the /// "lead" diagnostic; it will be given two arguments, the source and /// target types of the conversion. @@ -7049,186 +7085,207 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { return S.CheckUnresolvedMemberAccess(cast(E), D); } -/// ResolveAddressOfOverloadedFunction - Try to resolve the address of -/// an overloaded function (C++ [over.over]), where @p From is an -/// expression with overloaded function type and @p ToType is the type -/// we're trying to resolve to. For example: -/// -/// @code -/// int f(double); -/// int f(int); -/// -/// int (*pfd)(double) = f; // selects f(double) -/// @endcode -/// -/// This routine returns the resulting FunctionDecl if it could be -/// resolved, and NULL otherwise. When @p Complain is true, this -/// routine will emit diagnostics if there is an error. -FunctionDecl * -Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain, - DeclAccessPair &FoundResult) { - QualType FunctionType = ToType; - bool IsMember = false; - if (const PointerType *ToTypePtr = ToType->getAs()) - FunctionType = ToTypePtr->getPointeeType(); - else if (const ReferenceType *ToTypeRef = ToType->getAs()) - FunctionType = ToTypeRef->getPointeeType(); + + + +// [PossiblyAFunctionType] --> [Return] +// NonFunctionType --> NonFunctionType +// R (A) --> R(A) +// R (*)(A) --> R (A) +// R (&)(A) --> R (A) +// R (S::*)(A) --> R (A) +QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) { + QualType Ret = PossiblyAFunctionType; + if (const PointerType *ToTypePtr = + PossiblyAFunctionType->getAs()) + Ret = ToTypePtr->getPointeeType(); + else if (const ReferenceType *ToTypeRef = + PossiblyAFunctionType->getAs()) + Ret = ToTypeRef->getPointeeType(); else if (const MemberPointerType *MemTypePtr = - ToType->getAs()) { - FunctionType = MemTypePtr->getPointeeType(); - IsMember = true; - } + PossiblyAFunctionType->getAs()) + Ret = MemTypePtr->getPointeeType(); + Ret = + Context.getCanonicalType(Ret).getUnqualifiedType(); + return Ret; +} - // C++ [over.over]p1: - // [...] [Note: any redundant set of parentheses surrounding the - // overloaded function name is ignored (5.1). ] - // C++ [over.over]p1: - // [...] The overloaded function name can be preceded by the & - // operator. - // However, remember whether the expression has member-pointer form: - // C++ [expr.unary.op]p4: - // A pointer to member is only formed when an explicit & is used - // and its operand is a qualified-id not enclosed in - // parentheses. - OverloadExpr::FindResult Ovl = OverloadExpr::find(From); - OverloadExpr *OvlExpr = Ovl.Expression; +// A helper class to help with address of function resolution +// - allows us to avoid passing around all those ugly parameters +class AddressOfFunctionResolver +{ + Sema& S; + Expr* SourceExpr; + const QualType& TargetType; + QualType TargetFunctionType; // Extracted function type from target type + + bool Complain; + //DeclAccessPair& ResultFunctionAccessPair; + ASTContext& Context; - // We expect a pointer or reference to function, or a function pointer. - FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); - if (!FunctionType->isFunctionType()) { - if (Complain) - Diag(From->getLocStart(), diag::err_addr_ovl_not_func_ptrref) - << OvlExpr->getName() << ToType; + bool TargetTypeIsNonStaticMemberFunction; + bool FoundNonTemplateFunction; - return 0; - } - - // If the overload expression doesn't have the form of a pointer to - // member, don't try to convert it to a pointer-to-member type. - if (IsMember && !Ovl.HasFormOfMemberPointer) { - if (!Complain) return 0; - - // TODO: Should we condition this on whether any functions might - // have matched, or is it more appropriate to do that in callers? - // TODO: a fixit wouldn't hurt. - Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier) - << ToType << OvlExpr->getSourceRange(); - return 0; - } - - TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0; - if (OvlExpr->hasExplicitTemplateArgs()) { - OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); - ExplicitTemplateArgs = &ETABuffer; - } - - assert(From->getType() == Context.OverloadTy); - - // Look through all of the overloaded functions, searching for one - // whose type matches exactly. + OverloadExpr::FindResult OvlExprInfo; + OverloadExpr *OvlExpr; + TemplateArgumentListInfo OvlExplicitTemplateArgs; llvm::SmallVector, 4> Matches; - llvm::SmallVector NonMatches; - bool FoundNonTemplateFunction = false; - for (UnresolvedSetIterator I = OvlExpr->decls_begin(), - E = OvlExpr->decls_end(); I != E; ++I) { - // Look through any using declarations to find the underlying function. - NamedDecl *Fn = (*I)->getUnderlyingDecl(); - - // C++ [over.over]p3: - // Non-member functions and static member functions match - // targets of type "pointer-to-function" or "reference-to-function." - // Nonstatic member functions match targets of - // type "pointer-to-member-function." - // Note that according to DR 247, the containing class does not matter. - - if (FunctionTemplateDecl *FunctionTemplate - = dyn_cast(Fn)) { - if (CXXMethodDecl *Method - = dyn_cast(FunctionTemplate->getTemplatedDecl())) { - // Skip non-static function templates when converting to pointer, and - // static when converting to member pointer. - if (Method->isStatic() == IsMember) - continue; - } else if (IsMember) - continue; - - // C++ [over.over]p2: - // If the name is a function template, template argument deduction is - // done (14.8.2.2), and if the argument deduction succeeds, the - // resulting template argument list is used to generate a single - // function template specialization, which is added to the set of - // overloaded functions considered. - FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); - if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, - FunctionType, Specialization, Info)) { - // FIXME: make a note of the failed deduction for diagnostics. - (void)Result; - } else { - // Template argument deduction ensures that we have an exact match. - // This function template specicalization works. - Specialization = cast(Specialization->getCanonicalDecl()); - assert(FunctionType - == Context.getCanonicalType(Specialization->getType())); - Matches.push_back(std::make_pair(I.getPair(), Specialization)); +public: + AddressOfFunctionResolver(Sema &S, Expr* SourceExpr, + const QualType& TargetType, bool Complain) + : S(S), SourceExpr(SourceExpr), TargetType(TargetType), + Complain(Complain), Context(S.getASTContext()), + TargetTypeIsNonStaticMemberFunction( + !!TargetType->getAs()), + FoundNonTemplateFunction(false), + OvlExprInfo(OverloadExpr::find(SourceExpr)), + OvlExpr(OvlExprInfo.Expression) + { + ExtractUnqualifiedFunctionTypeFromTargetType(); + + if (!TargetFunctionType->isFunctionType()) { + if (OvlExpr->hasExplicitTemplateArgs()) { + DeclAccessPair dap; + if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization( + OvlExpr, false, &dap) ) { + Matches.push_back(std::make_pair(dap,Fn)); + } } - - continue; + return; } + + if (OvlExpr->hasExplicitTemplateArgs()) + OvlExpr->getExplicitTemplateArgs().copyInto(OvlExplicitTemplateArgs); + if (FindAllFunctionsThatMatchTargetTypeExactly()) { + // C++ [over.over]p4: + // If more than one function is selected, [...] + if (Matches.size() > 1) { + if (FoundNonTemplateFunction) + EliminateAllTemplateMatches(); + else + EliminateAllExceptMostSpecializedTemplate(); + } + } + } + +private: + bool isTargetTypeAFunction() const { + return TargetFunctionType->isFunctionType(); + } + + // [ToType] [Return] + + // R (*)(A) --> R (A), IsNonStaticMemberFunction = false + // R (&)(A) --> R (A), IsNonStaticMemberFunction = false + // R (S::*)(A) --> R (A), IsNonStaticMemberFunction = true + void inline ExtractUnqualifiedFunctionTypeFromTargetType() { + TargetFunctionType = S.ExtractUnqualifiedFunctionType(TargetType); + } + + // return true if any matching specializations were found + bool AddMatchingTemplateFunction(FunctionTemplateDecl* FunctionTemplate, + const DeclAccessPair& CurAccessFunPair) { + if (CXXMethodDecl *Method + = dyn_cast(FunctionTemplate->getTemplatedDecl())) { + // Skip non-static function templates when converting to pointer, and + // static when converting to member pointer. + if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction) + return false; + } + else if (TargetTypeIsNonStaticMemberFunction) + return false; + + // C++ [over.over]p2: + // If the name is a function template, template argument deduction is + // done (14.8.2.2), and if the argument deduction succeeds, the + // resulting template argument list is used to generate a single + // function template specialization, which is added to the set of + // overloaded functions considered. + FunctionDecl *Specialization = 0; + TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); + if (Sema::TemplateDeductionResult Result + = S.DeduceTemplateArguments(FunctionTemplate, + &OvlExplicitTemplateArgs, + TargetFunctionType, Specialization, + Info)) { + // FIXME: make a note of the failed deduction for diagnostics. + (void)Result; + return false; + } + + // Template argument deduction ensures that we have an exact match. + // This function template specicalization works. + Specialization = cast(Specialization->getCanonicalDecl()); + assert(TargetFunctionType + == Context.getCanonicalType(Specialization->getType())); + Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); + return true; + } + + bool AddMatchingNonTemplateFunction(NamedDecl* Fn, + const DeclAccessPair& CurAccessFunPair) { if (CXXMethodDecl *Method = dyn_cast(Fn)) { // Skip non-static functions when converting to pointer, and static // when converting to member pointer. - if (Method->isStatic() == IsMember) - continue; - - // If we have explicit template arguments, skip non-templates. - if (OvlExpr->hasExplicitTemplateArgs()) - continue; - } else if (IsMember) - continue; + if (Method->isStatic() == TargetTypeIsNonStaticMemberFunction) + return false; + } + else if (TargetTypeIsNonStaticMemberFunction) + return false; if (FunctionDecl *FunDecl = dyn_cast(Fn)) { QualType ResultTy; - if (Context.hasSameUnqualifiedType(FunctionType, FunDecl->getType()) || - IsNoReturnConversion(Context, FunDecl->getType(), FunctionType, + if (Context.hasSameUnqualifiedType(TargetFunctionType, + FunDecl->getType()) || + IsNoReturnConversion(Context, FunDecl->getType(), TargetFunctionType, ResultTy)) { - Matches.push_back(std::make_pair(I.getPair(), - cast(FunDecl->getCanonicalDecl()))); + Matches.push_back(std::make_pair(CurAccessFunPair, + cast(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; + return true; } } + + return false; + } + + bool FindAllFunctionsThatMatchTargetTypeExactly() { + bool Ret = false; + + // If the overload expression doesn't have the form of a pointer to + // member, don't try to convert it to a pointer-to-member type. + if (IsInvalidFormOfPointerToMemberFunction()) + return false; + + for (UnresolvedSetIterator I = OvlExpr->decls_begin(), + E = OvlExpr->decls_end(); + I != E; ++I) { + // Look through any using declarations to find the underlying function. + NamedDecl *Fn = (*I)->getUnderlyingDecl(); + + // C++ [over.over]p3: + // Non-member functions and static member functions match + // targets of type "pointer-to-function" or "reference-to-function." + // Nonstatic member functions match targets of + // type "pointer-to-member-function." + // Note that according to DR 247, the containing class does not matter. + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast(Fn)) { + if (AddMatchingTemplateFunction(FunctionTemplate, I.getPair())) + Ret = true; + } + // If we have explicit template arguments supplied, skip non-templates. + else if (!OvlExpr->hasExplicitTemplateArgs() && + AddMatchingNonTemplateFunction(Fn, I.getPair())) + Ret = true; + } + assert(Ret || Matches.empty()); + return Ret; } - // If there were 0 or 1 matches, we're done. - if (Matches.empty()) { - if (Complain) { - Diag(From->getLocStart(), diag::err_addr_ovl_no_viable) - << OvlExpr->getName() << FunctionType; - for (UnresolvedSetIterator I = OvlExpr->decls_begin(), - E = OvlExpr->decls_end(); - I != E; ++I) - if (FunctionDecl *F = dyn_cast((*I)->getUnderlyingDecl())) - NoteOverloadCandidate(F); - } - - return 0; - } else if (Matches.size() == 1) { - FunctionDecl *Result = Matches[0].second; - FoundResult = Matches[0].first; - MarkDeclarationReferenced(From->getLocStart(), Result); - if (Complain) { - CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); - } - return Result; - } - - // C++ [over.over]p4: - // If more than one function is selected, [...] - if (!FoundNonTemplateFunction) { + void EliminateAllExceptMostSpecializedTemplate() { // [...] and any given function template specialization F1 is // eliminated if the set contains a second function template // specialization whose function template is more specialized @@ -7245,54 +7302,127 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, MatchesCopy.addDecl(Matches[I].second, Matches[I].first.getAccess()); UnresolvedSetIterator Result = - getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), - TPOC_Other, 0, From->getLocStart(), - PDiag(), - PDiag(diag::err_addr_ovl_ambiguous) - << Matches[0].second->getDeclName(), - PDiag(diag::note_ovl_candidate) - << (unsigned) oc_function_template); - if (Result == MatchesCopy.end()) - return 0; + S.getMostSpecialized(MatchesCopy.begin(), MatchesCopy.end(), + TPOC_Other, 0, SourceExpr->getLocStart(), + S.PDiag(), + S.PDiag(diag::err_addr_ovl_ambiguous) + << Matches[0].second->getDeclName(), + S.PDiag(diag::note_ovl_candidate) + << (unsigned) oc_function_template, + Complain); - MarkDeclarationReferenced(From->getLocStart(), *Result); - FoundResult = Matches[Result - MatchesCopy.begin()].first; - if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, FoundResult); - return cast(*Result); - } - - // [...] any function template specializations in the set are - // eliminated if the set also contains a non-template function, [...] - for (unsigned I = 0, N = Matches.size(); I != N; ) { - if (Matches[I].second->getPrimaryTemplate() == 0) - ++I; - else { - Matches[I] = Matches[--N]; - Matches.set_size(N); + if (Result != MatchesCopy.end()) { + // Make it the first and only element + Matches[0].first = Matches[Result - MatchesCopy.begin()].first; + Matches[0].second = cast(*Result); + Matches.resize(1); } } - // [...] After such eliminations, if any, there shall remain exactly one - // selected function. - if (Matches.size() == 1) { - MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); - FoundResult = Matches[0].first; + void EliminateAllTemplateMatches() { + // [...] any function template specializations in the set are + // eliminated if the set also contains a non-template function, [...] + for (unsigned I = 0, N = Matches.size(); I != N; ) { + if (Matches[I].second->getPrimaryTemplate() == 0) + ++I; + else { + Matches[I] = Matches[--N]; + Matches.set_size(N); + } + } + } + +public: + void ComplainNoMatchesFound() const { + assert(Matches.empty()); + S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_no_viable) + << OvlExpr->getName() << TargetFunctionType + << OvlExpr->getSourceRange(); + S.NoteAllOverloadCandidates(OvlExpr); + } + + bool IsInvalidFormOfPointerToMemberFunction() const { + return TargetTypeIsNonStaticMemberFunction && + !OvlExprInfo.HasFormOfMemberPointer; + } + + void ComplainIsInvalidFormOfPointerToMemberFunction() const { + // TODO: Should we condition this on whether any functions might + // have matched, or is it more appropriate to do that in callers? + // TODO: a fixit wouldn't hurt. + S.Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier) + << TargetType << OvlExpr->getSourceRange(); + } + + void ComplainOfInvalidConversion() const { + S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_not_func_ptrref) + << OvlExpr->getName() << TargetType; + } + + void ComplainMultipleMatchesFound() const { + assert(Matches.size() > 1); + S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous) + << OvlExpr->getName() + << OvlExpr->getSourceRange(); + S.NoteAllOverloadCandidates(OvlExpr); + } + + int getNumMatches() const { return Matches.size(); } + + FunctionDecl* getMatchingFunctionDecl() const { + if (Matches.size() != 1) return 0; + return Matches[0].second; + } + + const DeclAccessPair* getMatchingFunctionAccessPair() const { + if (Matches.size() != 1) return 0; + return &Matches[0].first; + } +}; + +/// ResolveAddressOfOverloadedFunction - Try to resolve the address of +/// an overloaded function (C++ [over.over]), where @p From is an +/// expression with overloaded function type and @p ToType is the type +/// we're trying to resolve to. For example: +/// +/// @code +/// int f(double); +/// int f(int); +/// +/// int (*pfd)(double) = f; // selects f(double) +/// @endcode +/// +/// This routine returns the resulting FunctionDecl if it could be +/// resolved, and NULL otherwise. When @p Complain is true, this +/// routine will emit diagnostics if there is an error. +FunctionDecl * +Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, + bool Complain, + DeclAccessPair &FoundResult) { + + assert(AddressOfExpr->getType() == Context.OverloadTy); + + AddressOfFunctionResolver Resolver(*this, AddressOfExpr, TargetType, Complain); + int NumMatches = Resolver.getNumMatches(); + FunctionDecl* Fn = 0; + if ( NumMatches == 0 && Complain) { + if (Resolver.IsInvalidFormOfPointerToMemberFunction()) + Resolver.ComplainIsInvalidFormOfPointerToMemberFunction(); + else + Resolver.ComplainNoMatchesFound(); + } + else if (NumMatches > 1 && Complain) + Resolver.ComplainMultipleMatchesFound(); + else if (NumMatches == 1) { + Fn = Resolver.getMatchingFunctionDecl(); + assert(Fn); + FoundResult = *Resolver.getMatchingFunctionAccessPair(); + MarkDeclarationReferenced(AddressOfExpr->getLocStart(), Fn); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); - return cast(Matches[0].second); + CheckAddressOfMemberAccess(AddressOfExpr, FoundResult); } - - // FIXME: We should probably return the same thing that BestViableFunction - // returns (even if we issue the diagnostics here). - 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; + + return Fn; } /// \brief Given an expression that refers to an overloaded function, try to @@ -7302,14 +7432,15 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, /// template, where that template-id refers to a single template whose template /// arguments are either provided by the template-id or have defaults, /// as described in C++0x [temp.arg.explicit]p3. -FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { +FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, + bool Complain, + DeclAccessPair* FoundResult) { // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - if (From->getType() != Context.OverloadTy) return 0; @@ -7353,10 +7484,20 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { } // Multiple matches; we can't resolve to a single declaration. - if (Matched) + if (Matched) { + if (FoundResult) + *FoundResult = DeclAccessPair(); + + if (Complain) { + Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) + << OvlExpr->getName(); + NoteAllOverloadCandidates(OvlExpr); + } return 0; - - Matched = Specialization; + } + + if ((Matched = Specialization) && FoundResult) + *FoundResult = I.getPair(); } return Matched; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 12ed3732e7..9a11c68e05 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1824,6 +1824,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // template arguments that we have against the template name, if the template // name refers to a single template. That's not a terribly common case, // though. + // foo could identify a single function unambiguously + // This approach does NOT work, since f(1); + // gets resolved prior to resorting to overload resolution + // i.e., template void f(double); + // vs template void f(U); // These should be filtered out by our callers. assert(!R.empty() && "empty lookup results when building templateid"); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 5a0359c5fd..fceeaa7fdd 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -3322,9 +3322,11 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag) { + const PartialDiagnostic &CandidateDiag, + bool Complain) { if (SpecBegin == SpecEnd) { - Diag(Loc, NoneDiag); + if (Complain) + Diag(Loc, NoneDiag); return SpecEnd; } @@ -3370,13 +3372,15 @@ Sema::getMostSpecialized(UnresolvedSetIterator SpecBegin, } // Diagnose the ambiguity. - Diag(Loc, AmbigDiag); + if (Complain) + Diag(Loc, AmbigDiag); + if (Complain) // FIXME: Can we order the candidates in some sane way? - for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) - Diag((*I)->getLocation(), CandidateDiag) - << getTemplateArgumentBindingsText( - cast(*I)->getPrimaryTemplate()->getTemplateParameters(), + for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) + Diag((*I)->getLocation(), CandidateDiag) + << getTemplateArgumentBindingsText( + cast(*I)->getPrimaryTemplate()->getTemplateParameters(), *cast(*I)->getTemplateSpecializationArgs()); return SpecEnd; diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp new file mode 100644 index 0000000000..f38a74e6e4 --- /dev/null +++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp @@ -0,0 +1,95 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t; + +namespace DontResolveTooEarly_WaitForOverloadResolution +{ + template T* f(int); // #1 + template T& f(U); // #2 + + void g() { + int *ip = f(1); // calls #1 + } + + template + T* f2(int); + template + T& f2(U); + + void g2() { + int*ip = (f2)(1); // ok + } + +} // End namespace + + template + void twoT() { } + template + void twoT(T) { } + + + void two() { }; //expected-note 5{{candidate}} + void two(int) { }; //expected-note 5{{candidate}} + + + + void one() { } + template + void oneT() { } + + template + void cant_resolve() { } //expected-note 3{{candidate}} + + template void cant_resolve(T) { }//expected-note 3{{candidate}} + + +int main() +{ + { static_cast(one); } + { (void)(one); } + { static_cast(oneT); } + { (void)(oneT); } + + { static_cast(two); } // expected-error {{address of overloaded}} + { (void)(two); } // expected-error {{address of overloaded}} + { static_cast(twoT); } + { (void)(twoT); } + + + { ptrdiff_t x = reinterpret_cast(oneT); } + { (void) reinterpret_cast(oneT); } + { (void) reinterpret_cast(one); } + { (void) reinterpret_cast(one); } + + { ptrdiff_t x = reinterpret_cast(twoT); } + { (void) reinterpret_cast(twoT); } + { (void) reinterpret_cast(two); } //expected-error {{reinterpret_cast}} + { (void) static_cast(two); } //ok + + { (void) reinterpret_cast(two); } //expected-error {{reinterpret_cast}} + { (void) reinterpret_cast(two); } //expected-error {{reinterpret_cast}} + + { bool b = (twoT); } // ok + { bool b = (twoT); } //ok + + { bool b = &twoT; //&foo; } + b = &(twoT); } + + { ptrdiff_t x = (ptrdiff_t) &twoT; + x = (ptrdiff_t) &twoT; } + + { ptrdiff_t x = (ptrdiff_t) twoT; + x = (ptrdiff_t) twoT; } + + + { ptrdiff_t x = (ptrdiff_t) &twoT; + x = (ptrdiff_t) &twoT; } + + { oneT; &oneT; } //expected-warning 2{{ expression result unused }} + { static_cast(cant_resolve); } // expected-error {{address of overload}} + { bool b = cant_resolve; } // expected-error {{address of overload}} + { (void) cant_resolve; } // expected-error {{address of overload}} + +} + + diff --git a/test/CXX/over/over.over/p2.cpp b/test/CXX/over/over.over/p2.cpp index 1c3d036b15..3e8d0f1d8c 100644 --- a/test/CXX/over/over.over/p2.cpp +++ b/test/CXX/over/over.over/p2.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template T f0(T, T); +template T f0(T, T); //expected-note{{candidate}} void test_f0() { int (*f0a)(int, int) = f0; diff --git a/test/CXX/over/over.over/p4.cpp b/test/CXX/over/over.over/p4.cpp index 7b5009ab6f..27d070eff2 100644 --- a/test/CXX/over/over.over/p4.cpp +++ b/test/CXX/over/over.over/p4.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -template T f0(T); +template T f0(T); // expected-note{{candidate function}} int f0(int); // expected-note{{candidate function}} void test_f0() { @@ -13,8 +13,6 @@ namespace N { int f0(int); // expected-note{{candidate function}} } -int f0(int); - void test_f0_2() { using namespace N; int (*fp0)(int) = f0; // expected-error{{address of overloaded function 'f0' is ambiguous}} diff --git a/test/SemaCXX/addr-of-overloaded-function-casting.cpp b/test/SemaCXX/addr-of-overloaded-function-casting.cpp index 49abdea029..cfd55eed81 100644 --- a/test/SemaCXX/addr-of-overloaded-function-casting.cpp +++ b/test/SemaCXX/addr-of-overloaded-function-casting.cpp @@ -4,8 +4,8 @@ void g(); void f(); // expected-note 9{{candidate function}} void f(int); // expected-note 9{{candidate function}} -template void t(T); // expected-note 3{{candidate function}} -template void t(T*); // expected-note 3{{candidate function}} +template void t(T); // expected-note 6{{candidate function}} +template void t(T*); // expected-note 6{{candidate function}} template void u(T); diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp index 00d91043e4..a1079ff5ba 100644 --- a/test/SemaCXX/addr-of-overloaded-function.cpp +++ b/test/SemaCXX/addr-of-overloaded-function.cpp @@ -57,11 +57,11 @@ struct B struct C { C &getC() { - return makeAC; // expected-error{{address of overloaded function 'makeAC' cannot be converted to type 'C'}} + return makeAC; // expected-error{{address of overloaded function 'makeAC'}} } - C &makeAC(); - const C &makeAC() const; + C &makeAC(); //expected-note{{candidate function}} + const C &makeAC() const; //expected-note{{candidate function}} static void f(); // expected-note{{candidate function}} static void f(int); // expected-note{{candidate function}}