Author: gbiv Date: Tue Jun 7 19:34:22 2016 New Revision: 272080 URL: http://llvm.org/viewvc/llvm-project?rev=272080&view=rev Log: [Sema] Teach CheckPlaceholderExpr about unaddressable functions.
Given the following C++: ``` void foo(); void foo() __attribute__((enable_if(false, ""))); bool bar() { auto P = foo; return P == foo; } ``` We'll currently happily (and correctly) resolve `foo` to the `foo` overload without `enable_if` when assigning to `P`. However, we'll complain about an ambiguous overload on the `P == foo` line, because `Sema::CheckPlaceholderExpr` doesn't recognize that there's only one `foo` that could possibly work here. This patch teaches `Sema::CheckPlaceholderExpr` how to properly deal with such cases. Grepping for other callers of things like `Sema::ResolveAndFixSingleFunctionTemplateSpecialization`, it *looks* like this is the last place that needed to be fixed up. If I'm wrong, I'll see if there's something we can do that beats what amounts to whack-a-mole with bugs. Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaCast.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/SemaCXX/unaddressable-functions.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=272080&r1=272079&r2=272080&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Jun 7 19:34:22 2016 @@ -2567,6 +2567,8 @@ public: resolveAddressOfOnlyViableOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); + bool resolveAndFixAddressOfOnlyViableOverloadCandidate(ExprResult &SrcExpr); + FunctionDecl * ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, Modified: cfe/trunk/lib/Sema/SemaCast.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=272080&r1=272079&r2=272080&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCast.cpp (original) +++ cfe/trunk/lib/Sema/SemaCast.cpp Tue Jun 7 19:34:22 2016 @@ -1862,24 +1862,12 @@ static bool fixOverloadedReinterpretCast 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, Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=272080&r1=272079&r2=272080&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Jun 7 19:34:22 2016 @@ -14911,16 +14911,20 @@ ExprResult Sema::CheckPlaceholderExpr(Ex 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. Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=272080&r1=272079&r2=272080&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Jun 7 19:34:22 2016 @@ -10729,6 +10729,36 @@ Sema::resolveAddressOfOnlyViableOverload 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. /// Modified: cfe/trunk/test/SemaCXX/unaddressable-functions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/unaddressable-functions.cpp?rev=272080&r1=272079&r2=272080&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/unaddressable-functions.cpp (original) +++ cfe/trunk/test/SemaCXX/unaddressable-functions.cpp Tue Jun 7 19:34:22 2016 @@ -100,3 +100,48 @@ auto Fail = call(&foo); // expected-erro 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}} + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits