diff options
author | George Burgess IV <george.burgess.iv@gmail.com> | 2016-03-23 02:33:58 +0000 |
---|---|---|
committer | George Burgess IV <george.burgess.iv@gmail.com> | 2016-03-23 02:33:58 +0000 |
commit | 6da4c20f7daa6b42205c4642d7672b0c5015ed8f (patch) | |
tree | f1b4a224491b14321d585b9656ed9e23e3187dcd /clang/lib/Sema/SemaOverload.cpp | |
parent | a5b2972977802227e9c3d038819b73dcb011e521 (diff) | |
download | bcm5719-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.cpp | 31 |
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; |