summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorGeorge Burgess IV <george.burgess.iv@gmail.com>2016-03-23 02:33:58 +0000
committerGeorge Burgess IV <george.burgess.iv@gmail.com>2016-03-23 02:33:58 +0000
commit6da4c20f7daa6b42205c4642d7672b0c5015ed8f (patch)
treef1b4a224491b14321d585b9656ed9e23e3187dcd /clang/lib/Sema/SemaOverload.cpp
parenta5b2972977802227e9c3d038819b73dcb011e521 (diff)
downloadbcm5719-llvm-6da4c20f7daa6b42205c4642d7672b0c5015ed8f.tar.gz
bcm5719-llvm-6da4c20f7daa6b42205c4642d7672b0c5015ed8f.zip
[Sema] Allow implicit conversions of &overloaded_fn in C.
Also includes a minor ``enable_if`` docs update. Currently, our address-of overload machinery will only allow implicit conversions of overloaded functions to void* in C. For example: ``` void f(int) __attribute__((overloadable)); void f(double) __attribute__((overloadable, enable_if(0, ""))); void *fp = f; // OK. This is C and the target is void*. void (*fp2)(void) = f; // Error. This is C, but the target isn't void*. ``` This patch makes the assignment of `fp2` select the `f(int)` overload, rather than emitting an error (N.B. you'll still get a warning about the `fp2` assignment if you use -Wincompatible-pointer-types). Differential Revision: http://reviews.llvm.org/D13704 llvm-svn: 264132
Diffstat (limited to 'clang/lib/Sema/SemaOverload.cpp')
-rw-r--r--clang/lib/Sema/SemaOverload.cpp31
1 files changed, 20 insertions, 11 deletions
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 3bb9a26c438..cf7fb557a75 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -8488,7 +8488,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// Cand1's first N enable_if attributes have precisely the same conditions as
// Cand2's first N enable_if attributes (where N = the number of enable_if
// attributes on Cand2), and Cand1 has more than N enable_if attributes.
-static bool hasBetterEnableIfAttrs(Sema &S, const FunctionDecl *Cand1,
+static bool hasBetterEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
const FunctionDecl *Cand2) {
// FIXME: The next several lines are just
@@ -10299,13 +10299,25 @@ public:
bool hasComplained() const { return HasComplained; }
private:
- // Is A considered a better overload candidate for the desired type than B?
+ bool candidateHasExactlyCorrectType(const FunctionDecl *FD) {
+ QualType Discard;
+ return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) ||
+ S.IsNoReturnConversion(FD->getType(), TargetFunctionType, Discard);
+ }
+
+ /// \return true if A is considered a better overload candidate for the
+ /// desired type than B.
bool isBetterCandidate(const FunctionDecl *A, const FunctionDecl *B) {
- return hasBetterEnableIfAttrs(S, A, B);
+ // If A doesn't have exactly the correct type, we don't want to classify it
+ // as "better" than anything else. This way, the user is required to
+ // disambiguate for us if there are multiple candidates and no exact match.
+ return candidateHasExactlyCorrectType(A) &&
+ (!candidateHasExactlyCorrectType(B) ||
+ hasBetterEnableIfAttrs(S, A, B));
}
- // Returns true if we've eliminated any (read: all but one) candidates, false
- // otherwise.
+ /// \return true if we were able to eliminate all but one overload candidate,
+ /// false otherwise.
bool eliminiateSuboptimalOverloadCandidates() {
// Same algorithm as overload resolution -- one pass to pick the "best",
// another pass to be sure that nothing is better than the best.
@@ -10418,12 +10430,9 @@ private:
if (!S.checkAddressOfFunctionIsAvailable(FunDecl))
return false;
- QualType ResultTy;
- if (Context.hasSameUnqualifiedType(TargetFunctionType,
- FunDecl->getType()) ||
- S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType,
- ResultTy) ||
- (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())) {
+ // If we're in C, we need to support types that aren't exactly identical.
+ if (!S.getLangOpts().CPlusPlus ||
+ candidateHasExactlyCorrectType(FunDecl)) {
Matches.push_back(std::make_pair(
CurAccessFunPair, cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
FoundNonTemplateFunction = true;
OpenPOWER on IntegriCloud