From: George Burgess IV Date: Thu, 13 Apr 2017 23:47:08 +0000 (+0000) Subject: Fix PR31934: forming refs to functions with enable_if attrs. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3915a28878389759607b4562eba548dedf216298;p=clang Fix PR31934: forming refs to functions with enable_if attrs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@300283 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index b6f799b621..0d96304f4a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -6684,6 +6684,19 @@ InitializationSequence::Perform(Sema &S, if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); + // We don't check for e.g. function pointers here, since address + // availability checks should only occur when the function first decays + // into a pointer or reference. + if (CurInit.get()->getType()->isFunctionProtoType()) { + if (auto *DRE = dyn_cast(CurInit.get()->IgnoreParens())) { + if (auto *FD = dyn_cast(DRE->getDecl())) { + if (!S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, + DRE->getLocStart())) + return ExprError(); + } + } + } + // Even though we didn't materialize a temporary, the binding may still // extend the lifetime of a temporary. This happens if we bind a reference // to the result of a cast to reference type. diff --git a/test/SemaCXX/enable_if.cpp b/test/SemaCXX/enable_if.cpp index 01b6f8fd3a..9a06d38661 100644 --- a/test/SemaCXX/enable_if.cpp +++ b/test/SemaCXX/enable_if.cpp @@ -472,3 +472,30 @@ namespace instantiate_constexpr_in_enable_if { }; void g() { X().f(); } } + +namespace PR31934 { +int foo(int a) __attribute__((enable_if(a, ""))); +int runFn(int (&)(int)); + +void run() { + { + int (&bar)(int) = foo; // expected-error{{cannot take address of function 'foo'}} + int baz = runFn(foo); // expected-error{{cannot take address of function 'foo'}} + } + + { + int (&bar)(int) = (foo); // expected-error{{cannot take address of function 'foo'}} + int baz = runFn((foo)); // expected-error{{cannot take address of function 'foo'}} + } + + { + int (&bar)(int) = static_cast(foo); // expected-error{{cannot take address of function 'foo'}} + int baz = runFn(static_cast(foo)); // expected-error{{cannot take address of function 'foo'}} + } + + { + int (&bar)(int) = static_cast((foo)); // expected-error{{cannot take address of function 'foo'}} + int baz = runFn(static_cast((foo))); // expected-error{{cannot take address of function 'foo'}} + } +} +}