Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -2507,6 +2507,10 @@ bool *pHadMultipleCandidates = nullptr); FunctionDecl * + resolveAddressOfOnlyViableOverloadCandidate(Expr *E, + DeclAccessPair &FoundResult); + + FunctionDecl * ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, DeclAccessPair *Found = nullptr); Index: cfe/trunk/lib/Sema/SemaCast.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCast.cpp +++ cfe/trunk/lib/Sema/SemaCast.cpp @@ -1750,6 +1750,44 @@ } } +static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType, + ExprResult &Result) { + // We can only fix an overloaded reinterpret_cast if + // - it is a template with explicit arguments that resolves to an lvalue + // unambiguously, or + // - it is the only function in an overload set that may have its address + // taken. + + Expr *E = Result.get(); + // TODO: what if this fails because of DiagnoseUseOfDecl or something + // like it? + if (Self.ResolveAndFixSingleFunctionTemplateSpecialization( + Result, + Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr + ) && + Result.isUsable()) + return true; + + DeclAccessPair DAP; + FunctionDecl *Found = Self.resolveAddressOfOnlyViableOverloadCandidate(E, DAP); + if (!Found) + 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(); +} + static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, SourceRange OpRange, @@ -1761,21 +1799,15 @@ QualType SrcType = SrcExpr.get()->getType(); // Is the source an overloaded name? (i.e. &foo) - // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ... + // If so, reinterpret_cast generally can not help us here (13.4, p1, bullet 5) if (SrcType == Self.Context.OverloadTy) { - // ... unless foo resolves to an lvalue unambiguously. - // TODO: what if this fails because of DiagnoseUseOfDecl or something - // like it? - ExprResult SingleFunctionExpr = SrcExpr; - if (Self.ResolveAndFixSingleFunctionTemplateSpecialization( - SingleFunctionExpr, - Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr - ) && SingleFunctionExpr.isUsable()) { - SrcExpr = SingleFunctionExpr; - SrcType = SrcExpr.get()->getType(); - } else { + ExprResult FixedExpr = SrcExpr; + if (!fixOverloadedReinterpretCastExpr(Self, DestType, FixedExpr)) return TC_NotApplicable; - } + + assert(FixedExpr.isUsable() && "Invalid result fixing overloaded expr"); + SrcExpr = FixedExpr; + SrcType = SrcExpr.get()->getType(); } if (const ReferenceType *DestTypeTmp = DestType->getAs()) { Index: cfe/trunk/lib/Sema/SemaOverload.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp +++ cfe/trunk/lib/Sema/SemaOverload.cpp @@ -10419,7 +10419,7 @@ return false; QualType ResultTy; - if (Context.hasSameUnqualifiedType(TargetFunctionType, + if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType, ResultTy) || @@ -10652,6 +10652,42 @@ } /// \brief Given an expression that refers to an overloaded function, try to +/// resolve that function to a single function that can have its address taken. +/// This will modify `Pair` iff it returns non-null. +/// +/// This routine can only realistically succeed if all but one candidates in the +/// overload set for SrcExpr cannot have their addresses taken. +FunctionDecl * +Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E, + DeclAccessPair &Pair) { + OverloadExpr::FindResult R = OverloadExpr::find(E); + OverloadExpr *Ovl = R.Expression; + FunctionDecl *Result = nullptr; + DeclAccessPair DAP; + // Don't use the AddressOfResolver because we're specifically looking for + // cases where we have one overload candidate that lacks + // enable_if/pass_object_size/... + for (auto I = Ovl->decls_begin(), E = Ovl->decls_end(); I != E; ++I) { + auto *FD = dyn_cast(I->getUnderlyingDecl()); + if (!FD) + return nullptr; + + if (!checkAddressOfFunctionIsAvailable(FD)) + continue; + + // We have more than one result; quit. + if (Result) + return nullptr; + DAP = I.getPair(); + Result = FD; + } + + if (Result) + Pair = DAP; + return Result; +} + +/// \brief Given an expression that refers to an overloaded function, try to /// resolve that overloaded function expression down to a single function. /// /// This routine can only resolve template-ids that refer to a single function Index: cfe/trunk/test/SemaCXX/enable_if.cpp =================================================================== --- cfe/trunk/test/SemaCXX/enable_if.cpp +++ cfe/trunk/test/SemaCXX/enable_if.cpp @@ -253,3 +253,96 @@ a = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' becuase it has one or more non-tautological enable_if conditions}} } } + +namespace casting { +using VoidFnTy = void (*)(); + +void foo(void *c) __attribute__((enable_if(0, ""))); +void foo(int *c) __attribute__((enable_if(c, ""))); +void foo(char *c) __attribute__((enable_if(1, ""))); + +void testIt() { + auto A = reinterpret_cast(foo); + auto AAmp = reinterpret_cast(&foo); + + using VoidFooTy = void (*)(void *); + auto B = reinterpret_cast(foo); + auto BAmp = reinterpret_cast(&foo); + + using IntFooTy = void (*)(int *); + auto C = reinterpret_cast(foo); + auto CAmp = reinterpret_cast(&foo); + + using CharFooTy = void (*)(void *); + auto D = reinterpret_cast(foo); + auto DAmp = reinterpret_cast(&foo); +} + +void testItCStyle() { + auto A = (VoidFnTy)foo; + auto AAmp = (VoidFnTy)&foo; + + using VoidFooTy = void (*)(void *); + auto B = (VoidFooTy)foo; + auto BAmp = (VoidFooTy)&foo; + + using IntFooTy = void (*)(int *); + auto C = (IntFooTy)foo; + auto CAmp = (IntFooTy)&foo; + + using CharFooTy = void (*)(void *); + auto D = (CharFooTy)foo; + auto DAmp = (CharFooTy)&foo; +} +} + +namespace casting_templates { +template void foo(T) {} // expected-note 4 {{candidate function}} + +void foo(int *c) __attribute__((enable_if(c, ""))); //expected-note 4 {{candidate function}} +void foo(char *c) __attribute__((enable_if(c, ""))); //expected-note 4 {{candidate function}} + +void testIt() { + using IntFooTy = void (*)(int *); + auto A = reinterpret_cast(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} + auto ARef = reinterpret_cast(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} + auto AExplicit = reinterpret_cast(foo); + + using CharFooTy = void (*)(char *); + auto B = reinterpret_cast(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} + auto BRef = reinterpret_cast(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} + auto BExplicit = reinterpret_cast(foo); +} + +void testItCStyle() { + // constexpr is usable here because all of these should become static_casts. + using IntFooTy = void (*)(int *); + constexpr auto A = (IntFooTy)foo; + constexpr auto ARef = (IntFooTy)&foo; + constexpr auto AExplicit = (IntFooTy)foo; + + using CharFooTy = void (*)(char *); + constexpr auto B = (CharFooTy)foo; + constexpr auto BRef = (CharFooTy)&foo; + constexpr auto BExplicit = (CharFooTy)foo; + + static_assert(A == ARef && ARef == AExplicit, ""); + static_assert(B == BRef && BRef == BExplicit, ""); +} +} + +namespace multiple_matches { +using NoMatchTy = void (*)(); + +void foo(float *c); //expected-note 4 {{candidate function}} +void foo(int *c) __attribute__((enable_if(1, ""))); //expected-note 4 {{candidate function}} +void foo(char *c) __attribute__((enable_if(1, ""))); //expected-note 4 {{candidate function}} + +void testIt() { + auto A = reinterpret_cast(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} + auto ARef = reinterpret_cast(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} + + auto C = (NoMatchTy)foo; // expected-error{{address of overloaded function 'foo' does not match required type 'void ()'}} + auto CRef = (NoMatchTy)&foo; // expected-error{{address of overloaded function 'foo' does not match required type 'void ()'}} +} +} Index: cfe/trunk/test/SemaCXX/unaddressable-functions.cpp =================================================================== --- cfe/trunk/test/SemaCXX/unaddressable-functions.cpp +++ cfe/trunk/test/SemaCXX/unaddressable-functions.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14 + +namespace access_control { +class Private { + void check(int *) __attribute__((enable_if(false, ""))); + void check(double *) __attribute__((enable_if(true, ""))); + + static void checkStatic(int *) __attribute__((enable_if(false, ""))); + static void checkStatic(double *) __attribute__((enable_if(true, ""))); +}; + +auto Priv = reinterpret_cast(&Private::check); // expected-error{{'check' is a private member of 'access_control::Private'}} expected-note@6{{implicitly declared private here}} + +auto PrivStatic = reinterpret_cast(&Private::checkStatic); // expected-error{{'checkStatic' is a private member of 'access_control::Private'}} expected-note@9{{implicitly declared private here}} + +class Protected { +protected: + void check(int *) __attribute__((enable_if(false, ""))); + void check(double *) __attribute__((enable_if(true, ""))); + + static void checkStatic(int *) __attribute__((enable_if(false, ""))); + static void checkStatic(double *) __attribute__((enable_if(true, ""))); +}; + +auto Prot = reinterpret_cast(&Protected::check); // expected-error{{'check' is a protected member of 'access_control::Protected'}} expected-note@19{{declared protected here}} + +auto ProtStatic = reinterpret_cast(&Protected::checkStatic); // expected-error{{'checkStatic' is a protected member of 'access_control::Protected'}} expected-note@22{{declared protected here}} +} + +namespace unavailable { +// Ensure that we check that the function can be called +void foo() __attribute__((unavailable("don't call this"))); +void foo(int) __attribute__((enable_if(false, ""))); + +void *Ptr = reinterpret_cast(foo); // expected-error{{'foo' is unavailable: don't call this}} expected-note@-3{{explicitly marked unavailable here}} +}