r257016 - [Sema] Teach overload resolution about unaddressable functions.

George Burgess IV via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 6 18:26:58 PST 2016


Author: gbiv
Date: Wed Jan  6 20:26:57 2016
New Revision: 257016

URL: http://llvm.org/viewvc/llvm-project?rev=257016&view=rev
Log:
[Sema] Teach overload resolution about unaddressable functions.

Given an expression like `(&Foo)();`, we perform overload resolution as
if we are calling `Foo` directly. This causes problems if `Foo` is a
function that can't have its address taken. This patch teaches overload
resolution to ignore functions that can't have their address taken in
such cases.

Differential Revision: http://reviews.llvm.org/D15590

Modified:
    cfe/trunk/include/clang/Sema/Overload.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CodeGenCXX/pass-object-size.cpp
    cfe/trunk/test/Sema/pass-object-size.c
    cfe/trunk/test/SemaCXX/pass-object-size.cpp

Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=257016&r1=257015&r2=257016&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Wed Jan  6 20:26:57 2016
@@ -570,8 +570,8 @@ namespace clang {
     /// This conversion candidate is not viable because its result
     /// type is not implicitly convertible to the desired type.
     ovl_fail_bad_final_conversion,
-    
-    /// This conversion function template specialization candidate is not 
+
+    /// This conversion function template specialization candidate is not
     /// viable because the final conversion was not an exact match.
     ovl_fail_final_conversion_not_exact,
 
@@ -582,7 +582,10 @@ namespace clang {
 
     /// This candidate function was not viable because an enable_if
     /// attribute disabled it.
-    ovl_fail_enable_if
+    ovl_fail_enable_if,
+
+    /// This candidate was not viable because its address could not be taken.
+    ovl_fail_addr_not_available
   };
 
   /// OverloadCandidate - A single candidate in an overload set (C++ 13.3).

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=257016&r1=257015&r2=257016&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Jan  6 20:26:57 2016
@@ -2548,7 +2548,8 @@ public:
                                      MultiExprArg Args,
                                      SourceLocation RParenLoc,
                                      Expr *ExecConfig,
-                                     bool AllowTypoCorrection=true);
+                                     bool AllowTypoCorrection=true,
+                                     bool CalleesAddressIsTaken=false);
 
   bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
                               MultiExprArg Args, SourceLocation RParenLoc,

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=257016&r1=257015&r2=257016&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jan  6 20:26:57 2016
@@ -4935,7 +4935,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn,
       OverloadExpr *ovl = find.Expression;
       if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl))
         return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs,
-                                       RParenLoc, ExecConfig);
+                                       RParenLoc, ExecConfig,
+                                       /*AllowTypoCorrection=*/true,
+                                       find.IsAddressOfOperand);
       return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs, RParenLoc);
     }
   }
@@ -4949,10 +4951,14 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn,
 
   Expr *NakedFn = Fn->IgnoreParens();
 
+  bool CallingNDeclIndirectly = false;
   NamedDecl *NDecl = nullptr;
-  if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn))
-    if (UnOp->getOpcode() == UO_AddrOf)
+  if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn)) {
+    if (UnOp->getOpcode() == UO_AddrOf) {
+      CallingNDeclIndirectly = true;
       NakedFn = UnOp->getSubExpr()->IgnoreParens();
+    }
+  }
 
   if (isa<DeclRefExpr>(NakedFn)) {
     NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
@@ -4974,6 +4980,11 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn,
     NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
 
   if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
+    if (CallingNDeclIndirectly &&
+        !checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+                                           Fn->getLocStart()))
+      return ExprError();
+
     if (FD->hasAttr<EnableIfAttr>()) {
       if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) {
         Diag(Fn->getLocStart(),

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=257016&r1=257015&r2=257016&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Jan  6 20:26:57 2016
@@ -9643,6 +9643,13 @@ static void NoteFunctionCandidate(Sema &
 
   case ovl_fail_enable_if:
     return DiagnoseFailedEnableIfAttr(S, Cand);
+
+  case ovl_fail_addr_not_available: {
+    bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function);
+    (void)Available;
+    assert(!Available);
+    break;
+  }
   }
 }
 
@@ -11245,6 +11252,17 @@ static ExprResult FinishOverloadedCallEx
   return ExprError();
 }
 
+static void markUnaddressableCandidatesUnviable(Sema &S,
+                                                OverloadCandidateSet &CS) {
+  for (auto I = CS.begin(), E = CS.end(); I != E; ++I) {
+    if (I->Viable &&
+        !S.checkAddressOfFunctionIsAvailable(I->Function, /*Complain=*/false)) {
+      I->Viable = false;
+      I->FailureKind = ovl_fail_addr_not_available;
+    }
+  }
+}
+
 /// BuildOverloadedCallExpr - Given the call expression that calls Fn
 /// (which eventually refers to the declaration Func) and the call
 /// arguments Args/NumArgs, attempt to resolve the function call down
@@ -11257,7 +11275,8 @@ ExprResult Sema::BuildOverloadedCallExpr
                                          MultiExprArg Args,
                                          SourceLocation RParenLoc,
                                          Expr *ExecConfig,
-                                         bool AllowTypoCorrection) {
+                                         bool AllowTypoCorrection,
+                                         bool CalleesAddressIsTaken) {
   OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
                                     OverloadCandidateSet::CSK_Normal);
   ExprResult result;
@@ -11266,6 +11285,11 @@ ExprResult Sema::BuildOverloadedCallExpr
                              &result))
     return result;
 
+  // If the user handed us something like `(&Foo)(Bar)`, we need to ensure that
+  // functions that aren't addressible are considered unviable.
+  if (CalleesAddressIsTaken)
+    markUnaddressableCandidatesUnviable(*this, CandidateSet);
+
   OverloadCandidateSet::iterator Best;
   OverloadingResult OverloadResult =
       CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best);

Modified: cfe/trunk/test/CodeGenCXX/pass-object-size.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/pass-object-size.cpp?rev=257016&r1=257015&r2=257016&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/pass-object-size.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/pass-object-size.cpp Wed Jan  6 20:26:57 2016
@@ -25,3 +25,21 @@ void Lambdas(char *ptr) {
 // CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_1clEPvU17pass_object_size0"
 // CHECK-NOT: call i64 @llvm.objectsize
 }
+
+// This is here instead of in Sema/ because we need to check to make sure the
+// proper function is called. If it's not, we'll end up with assertion errors.
+namespace addrof {
+void OvlFoo(void *const __attribute__((pass_object_size(0)))) {}
+void OvlFoo(int *const) {}
+
+// CHECK: define void @_ZN6addrof4TestEv
+void Test() {
+  // Treating parens-only calls as though they were direct is consistent with
+  // how we handle other implicitly unaddressable functions (e.g. builtins).
+  // CHECK: call void @_ZN6addrof6OvlFooEPvU17pass_object_size0
+  (OvlFoo)(nullptr);
+
+  // CHECK: call void @_ZN6addrof6OvlFooEPi
+  (&OvlFoo)(nullptr);
+}
+}

Modified: cfe/trunk/test/Sema/pass-object-size.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/pass-object-size.c?rev=257016&r1=257015&r2=257016&view=diff
==============================================================================
--- cfe/trunk/test/Sema/pass-object-size.c (original)
+++ cfe/trunk/test/Sema/pass-object-size.c Wed Jan  6 20:26:57 2016
@@ -33,7 +33,7 @@ void TakeFnOvl(void (*)(int *)) overload
 
 void NotOverloaded(void *p PS(0));
 void IsOverloaded(void *p PS(0)) overloaded;
-void IsOverloaded(char *p) overloaded;
+void IsOverloaded(char *p) overloaded; // char* inestead of void* is intentional
 void FunctionPtrs() {
   void (*p)(void *) = NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
   void (*p2)(void *) = &NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
@@ -49,4 +49,8 @@ void FunctionPtrs() {
 
   TakeFnOvl(NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
   TakeFnOvl(&NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+
+  int P;
+  (&NotOverloaded)(&P); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+  (&IsOverloaded)(&P); //expected-error{{no matching function}} expected-note at 35{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note at 36{{candidate function not viable: no known conversion from 'int *' to 'char *' for 1st argument}}
 }

Modified: cfe/trunk/test/SemaCXX/pass-object-size.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pass-object-size.cpp?rev=257016&r1=257015&r2=257016&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/pass-object-size.cpp (original)
+++ cfe/trunk/test/SemaCXX/pass-object-size.cpp Wed Jan  6 20:26:57 2016
@@ -120,3 +120,17 @@ void Bar() {
   (void)+[](void *const p __attribute__((pass_object_size(0)))) {}; //expected-error-re{{invalid argument type '(lambda at {{.*}})' to unary expression}}
 }
 }
+
+namespace ovlbug {
+// Directly calling an address-of function expression (e.g. in (&foo)(args...))
+// doesn't go through regular address-of-overload logic. This caused the above
+// code to generate an ICE.
+void DirectAddrOf(void *__attribute__((pass_object_size(0))));
+void DirectAddrOfOvl(void *__attribute__((pass_object_size(0))));
+void DirectAddrOfOvl(int *);
+
+void Test() {
+  (&DirectAddrOf)(nullptr); //expected-error{{cannot take address of function 'DirectAddrOf' because parameter 1 has pass_object_size attribute}}
+  (&DirectAddrOfOvl)((char*)nullptr); //expected-error{{no matching function}} expected-note at 129{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note at 130{{candidate function not viable: no known conversion from 'char *' to 'int *' for 1st argument}}
+}
+}




More information about the cfe-commits mailing list