]> granicus.if.org Git - clang/commitdiff
[Sema] Make typeof(OverloadedFunctionName) not a pointer.
authorGeorge Burgess IV <george.burgess.iv@gmail.com>
Tue, 9 May 2017 04:06:24 +0000 (04:06 +0000)
committerGeorge Burgess IV <george.burgess.iv@gmail.com>
Tue, 9 May 2017 04:06:24 +0000 (04:06 +0000)
We were sometimes doing a function->pointer conversion in
Sema::CheckPlaceholderExpr, which isn't the job of CheckPlaceholderExpr.

So, when we saw typeof(OverloadedFunctionName), where
OverloadedFunctionName referenced a name with only one function that
could have its address taken, we'd give back a function pointer type
instead of a function type. This is incorrect.

I kept the logic for doing the function pointer conversion in
resolveAndFixAddressOfOnlyViableOverloadCandidate because it was more
consistent with existing ResolveAndFix* methods.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@302506 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaCast.cpp
lib/Sema/SemaOverload.cpp
test/Sema/overloadable.c
test/SemaCXX/enable_if.cpp

index e5961079f7c2621d810068605ea2437d7dc64f69..b0cb34cf5653c762209ed678e06fd11e22846186 100644 (file)
@@ -2726,7 +2726,8 @@ public:
   resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
                                               DeclAccessPair &FoundResult);
 
-  bool resolveAndFixAddressOfOnlyViableOverloadCandidate(ExprResult &SrcExpr);
+  bool resolveAndFixAddressOfOnlyViableOverloadCandidate(
+      ExprResult &SrcExpr, bool DoFunctionPointerConversion = false);
 
   FunctionDecl *
   ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
index 7e91709e67da884048fb4787eccaec79ac3276a4..7d534263f4681b625080c22e884812a8a58bc61d 100644 (file)
@@ -1871,7 +1871,8 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
   // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
   // preserves Result.
   Result = E;
-  if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+  if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(
+          Result, /*DoFunctionPointerConversion=*/true))
     return false;
   return Result.isUsable();
 }
index 782c377e32025a279de12d5ab402dda3174bc3b6..51794160278ca237a8ad4255deb4bf6f4dd5442b 100644 (file)
@@ -11210,12 +11210,12 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
 /// \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.
+/// requested, potentially 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) {
+    ExprResult &SrcExpr, bool DoFunctionPointerConverion) {
   Expr *E = SrcExpr.get();
   assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
 
@@ -11230,7 +11230,7 @@ bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
   DiagnoseUseOfDecl(Found, E->getExprLoc());
   CheckAddressOfMemberAccess(E, DAP);
   Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found);
-  if (Fixed->getType()->isFunctionType())
+  if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType())
     SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
   else
     SrcExpr = Fixed;
index f5e17d211910837666c47afeaf0a2384066c5554..49d8085651d4d61cbe01013070497d13e3c4ff17 100644 (file)
@@ -151,3 +151,18 @@ void dropping_qualifiers_is_incompatible() {
   foo(ccharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@148{{candidate function}} expected-note@149{{candidate function}}
   foo(vcharbuf); // expected-error{{call to 'foo' is ambiguous}} expected-note@148{{candidate function}} expected-note@149{{candidate function}}
 }
+
+// Bug: we used to treat `__typeof__(foo)` as though it was `__typeof__(&foo)`
+// if `foo` was overloaded with only one function that could have its address
+// taken.
+void typeof_function_is_not_a_pointer() {
+  void not_a_pointer(void *) __attribute__((overloadable));
+  void not_a_pointer(char *__attribute__((pass_object_size(1))))
+    __attribute__((overloadable));
+
+  __typeof__(not_a_pointer) *fn;
+
+  void take_fn(void (*)(void *));
+  // if take_fn is passed a void (**)(void *), we'll get a warning.
+  take_fn(fn);
+}
index 9a06d386611024b011d98dcaf440f9fa2730bdea..93014f50d5080de6c753bc8c68ee7ad2d8fd6b69 100644 (file)
@@ -499,3 +499,17 @@ void run() {
   }
 }
 }
+
+namespace TypeOfFn {
+  template <typename T, typename U>
+  struct is_same;
+
+  template <typename T> struct is_same<T, T> {
+    enum { value = 1 };
+  };
+
+  void foo(int a) __attribute__((enable_if(a, "")));
+  void foo(float a) __attribute__((enable_if(1, "")));
+
+  static_assert(is_same<__typeof__(foo)*, decltype(&foo)>::value, "");
+}