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 |
|