diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCast.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 30 | ||||
-rw-r--r-- | clang/test/SemaCXX/unaddressable-functions.cpp | 45 |
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}} + } +} |