diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2132a5f2c3..7b38b25c80 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -666,6 +666,10 @@ def err_ovl_surrogate_cand : Note<"conversion candidate of type %0">; def err_member_call_without_object : Error< "call to non-static member function without an object argument">; +// C++ Address of Overloaded Function +def err_addr_ovl_ambiguous : Error< + "address of overloaded function %0 is ambiguous">; + // C++ Template Declarations def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index b7edc0149e..1efa175c73 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3742,7 +3742,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // Look through all of the overloaded functions, searching for one // whose type matches exactly. - // FIXME: We still need to cope with duplicates, partial ordering, etc. + llvm::SmallPtrSet Matches; + + bool FoundNonTemplateFunction = false; for (OverloadIterator FunEnd; Fun != FunEnd; ++Fun) { // C++ [over.over]p3: // Non-member functions and static member functions match @@ -3753,12 +3755,21 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, if (FunctionTemplateDecl *FunctionTemplate = dyn_cast(*Fun)) { - // C++ [temp.deduct.funcaddr]p1: - // Template arguments can be deduced from the type specified when - // taking the address of an overloaded function (13.4). The function - // template’s function type and the specified type are used as the - // types of P and A, and the deduction is done as described in - // 14.8.2.4. + 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); if (TemplateDeductionResult Result @@ -3770,7 +3781,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } else { assert(FunctionType == Context.getCanonicalType(Specialization->getType())); - return Specialization; + Matches.insert( + cast(Context.getCanonicalDecl(Specialization))); } } @@ -3779,15 +3791,54 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // when converting to member pointer. if (Method->isStatic() == IsMember) continue; - } else if (IsMember) // FIXME: member templates + } else if (IsMember) continue; if (FunctionDecl *FunDecl = dyn_cast(*Fun)) { - if (FunctionType == Context.getCanonicalType(FunDecl->getType())) - return FunDecl; + if (FunctionType == Context.getCanonicalType(FunDecl->getType())) { + Matches.insert(cast(Context.getCanonicalDecl(*Fun))); + FoundNonTemplateFunction = true; + } } } + // If there were 0 or 1 matches, we're done. + if (Matches.empty()) + return 0; + else if (Matches.size() == 1) + return *Matches.begin(); + + // C++ [over.over]p4: + // If more than one function is selected, [...] + llvm::SmallVector RemainingMatches; + if (FoundNonTemplateFunction) { + // [...] any function template specializations in the set are eliminated + // if the set also contains a non-template function, [...] + for (llvm::SmallPtrSet::iterator M = Matches.begin(), + MEnd = Matches.end(); + M != MEnd; ++M) + if ((*M)->getPrimaryTemplate() == 0) + RemainingMatches.push_back(*M); + } else { + // [...] and any given function template specialization F1 is eliminated + // if the set contains a second function template specialization whose + // function template is more specialized than the function template of F1 + // according to the partial ordering rules of 14.5.5.2. + // FIXME: Implement this! + RemainingMatches.append(Matches.begin(), Matches.end()); + } + + // [...] After such eliminations, if any, there shall remain exactly one + // selected function. + if (RemainingMatches.size() == 1) + return RemainingMatches.front(); + + // 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) + << RemainingMatches[0]->getDeclName(); + for (unsigned I = 0, N = RemainingMatches.size(); I != N; ++I) + Diag(RemainingMatches[I]->getLocation(), diag::err_ovl_candidate); return 0; } diff --git a/test/CXX/over/over.over/p4.cpp b/test/CXX/over/over.over/p4.cpp new file mode 100644 index 0000000000..a05dbaebb7 --- /dev/null +++ b/test/CXX/over/over.over/p4.cpp @@ -0,0 +1,23 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template T f0(T); +int f0(int); // expected-note{{candidate function}} + +void test_f0() { + int (*fp0)(int) = f0; + int (*fp1)(int) = &f0; + float (*fp2)(float) = &f0; +} + +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{{ambiguous}} \ + // expected-error{{initializing}} + float (*fp1)(float) = f0; +} diff --git a/www/cxx_status.html b/www/cxx_status.html index 61cf6493de..d3308608ef 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -1689,12 +1689,10 @@ welcome!

  13.4 [over.over] N/A - - + + N/A - Error messages need some work. Without templates or using - declarations, we don't have any ambiguities, so the semantic - analysis is incomplete. + No partial ordering of function templates.   13.5 [over.oper] @@ -2102,10 +2100,10 @@ welcome!

      14.8.2.2 [temp.deduct.funcaddr] - - - - + N/A + + + N/A