summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Sema/Sema.h2
-rw-r--r--clang/lib/Sema/SemaCast.cpp22
-rw-r--r--clang/lib/Sema/SemaExpr.cpp20
-rw-r--r--clang/lib/Sema/SemaOverload.cpp30
-rw-r--r--clang/test/SemaCXX/unaddressable-functions.cpp45
5 files changed, 94 insertions, 25 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 2e068cff890..62f37fda52d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2567,6 +2567,8 @@ public:
resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
DeclAccessPair &FoundResult);
+ bool resolveAndFixAddressOfOnlyViableOverloadCandidate(ExprResult &SrcExpr);
+
FunctionDecl *
ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
bool Complain = false,
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 7239d44ca23..df32dbdb150 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -1862,24 +1862,12 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
Result.isUsable())
return true;
- DeclAccessPair DAP;
- FunctionDecl *Found = Self.resolveAddressOfOnlyViableOverloadCandidate(E, DAP);
- if (!Found)
+ // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
+ // preserves Result.
+ Result = E;
+ if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
return false;
-
- // It seems that if we encounter a call to a function that is both unavailable
- // and inaccessible, we'll emit multiple diags for said call. Hence, we run
- // both checks below unconditionally.
- Self.DiagnoseUseOfDecl(Found, E->getExprLoc());
- Self.CheckAddressOfMemberAccess(E, DAP);
-
- Expr *Fixed = Self.FixOverloadedFunctionReference(E, DAP, Found);
- if (Fixed->getType()->isFunctionType())
- Result = Self.DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
- else
- Result = Fixed;
-
- return !Result.isInvalid();
+ return Result.isUsable();
}
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 29be09e8fea..f4a5dea8f94 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14911,16 +14911,20 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::Overload: {
// Try to resolve a single function template specialization.
// This is obligatory.
- ExprResult result = E;
- if (ResolveAndFixSingleFunctionTemplateSpecialization(result, false)) {
- return result;
+ ExprResult Result = E;
+ if (ResolveAndFixSingleFunctionTemplateSpecialization(Result, false))
+ return Result;
+
+ // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
+ // leaves Result unchanged on failure.
+ Result = E;
+ if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+ return Result;
// If that failed, try to recover with a call.
- } else {
- tryToRecoverWithCall(result, PDiag(diag::err_ovl_unresolvable),
- /*complain*/ true);
- return result;
- }
+ tryToRecoverWithCall(Result, PDiag(diag::err_ovl_unresolvable),
+ /*complain*/ true);
+ return Result;
}
// Bound member functions.
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 1c41487f5a4..baf673b5e68 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10729,6 +10729,36 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
return Result;
}
+/// \brief Given an overloaded function, tries to turn it into a non-overloaded
+/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This
+/// will perform access checks, diagnose the use of the resultant decl, and, if
+/// necessary, perform a function-to-pointer decay.
+///
+/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails.
+/// Otherwise, returns true. This may emit diagnostics and return true.
+bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ ExprResult &SrcExpr) {
+ Expr *E = SrcExpr.get();
+ assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
+
+ DeclAccessPair DAP;
+ FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP);
+ if (!Found)
+ return false;
+
+ // Emitting multiple diagnostics for a function that is both inaccessible and
+ // unavailable is consistent with our behavior elsewhere. So, always check
+ // for both.
+ DiagnoseUseOfDecl(Found, E->getExprLoc());
+ CheckAddressOfMemberAccess(E, DAP);
+ Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found);
+ if (Fixed->getType()->isFunctionType())
+ SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
+ else
+ SrcExpr = Fixed;
+ return true;
+}
+
/// \brief Given an expression that refers to an overloaded function, try to
/// resolve that overloaded function expression down to a single function.
///
diff --git a/clang/test/SemaCXX/unaddressable-functions.cpp b/clang/test/SemaCXX/unaddressable-functions.cpp
index 823f1be05f8..286cbee5ea9 100644
--- a/clang/test/SemaCXX/unaddressable-functions.cpp
+++ b/clang/test/SemaCXX/unaddressable-functions.cpp
@@ -100,3 +100,48 @@ auto Fail = call(&foo); // expected-error{{no matching function for call to 'cal
auto PtrOk = &foo<int>;
auto PtrFail = &foo; // expected-error{{variable 'PtrFail' with type 'auto' has incompatible initializer of type '<overloaded function type>'}}
}
+
+namespace pointer_equality {
+ using FnTy = void (*)();
+
+ void bothEnableIf() __attribute__((enable_if(false, "")));
+ void bothEnableIf() __attribute__((enable_if(true, "")));
+
+ void oneEnableIf() __attribute__((enable_if(false, "")));
+ void oneEnableIf();
+
+ void test() {
+ FnTy Fn;
+ (void)(Fn == bothEnableIf);
+ (void)(Fn == &bothEnableIf);
+ (void)(Fn == oneEnableIf);
+ (void)(Fn == &oneEnableIf);
+ }
+
+ void unavailableEnableIf() __attribute__((enable_if(false, "")));
+ void unavailableEnableIf() __attribute__((unavailable("noooo"))); // expected-note 2{{marked unavailable here}}
+
+ void testUnavailable() {
+ FnTy Fn;
+ (void)(Fn == unavailableEnableIf); // expected-error{{is unavailable}}
+ (void)(Fn == &unavailableEnableIf); // expected-error{{is unavailable}}
+ }
+
+ class Foo {
+ static void staticAccessEnableIf(); // expected-note 2{{declared private here}}
+ void accessEnableIf(); // expected-note{{declared private here}}
+
+ public:
+ static void staticAccessEnableIf() __attribute__((enable_if(false, "")));
+ void accessEnableIf() __attribute__((enable_if(false, "")));
+ };
+
+ void testAccess() {
+ FnTy Fn;
+ (void)(Fn == Foo::staticAccessEnableIf); // expected-error{{is a private member}}
+ (void)(Fn == &Foo::staticAccessEnableIf); // expected-error{{is a private member}}
+
+ void (Foo::*MemFn)();
+ (void)(MemFn == &Foo::accessEnableIf); // expected-error{{is a private member}}
+ }
+}
OpenPOWER on IntegriCloud