[cfe-commits] r151170 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm

Douglas Gregor dgregor at apple.com
Wed Feb 22 09:32:19 PST 2012


Author: dgregor
Date: Wed Feb 22 11:32:19 2012
New Revision: 151170

URL: http://llvm.org/viewvc/llvm-project?rev=151170&view=rev
Log:
Teach overload resolution to prefer user-defined conversion via a
lambda closure type's function pointer conversion over user-defined
conversion via a lambda closure type's block pointer conversion,
always. This is a preference for more-standard code (since blocks
are an extension)  and a nod to efficiency, since function pointers
don't require any memory management. Fixes PR12063.

Modified:
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=151170&r1=151169&r2=151170&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Feb 22 11:32:19 2012
@@ -3065,6 +3065,41 @@
   return true;
 }
 
+/// \brief Compare the user-defined conversion functions or constructors
+/// of two user-defined conversion sequences to determine whether any ordering
+/// is possible.
+static ImplicitConversionSequence::CompareKind
+compareConversionFunctions(Sema &S,
+                           FunctionDecl *Function1,
+                           FunctionDecl *Function2) {
+  if (!S.getLangOptions().ObjC1 || !S.getLangOptions().CPlusPlus0x)
+    return ImplicitConversionSequence::Indistinguishable;
+  
+  // Objective-C++:
+  //   If both conversion functions are implicitly-declared conversions from
+  //   a lambda closure type to a function pointer and a block pointer, 
+  //   respectively, always prefer the conversion to a function pointer,
+  //   because the function pointer is more lightweight and is more likely
+  //   to keep code working.
+  CXXConversionDecl *Conv1 = dyn_cast<CXXConversionDecl>(Function1);
+  if (!Conv1)
+    return ImplicitConversionSequence::Indistinguishable;
+    
+  CXXConversionDecl *Conv2 = dyn_cast<CXXConversionDecl>(Function2);
+  if (!Conv2)
+    return ImplicitConversionSequence::Indistinguishable;
+  
+  if (Conv1->getParent()->isLambda() && Conv2->getParent()->isLambda()) {
+    bool Block1 = Conv1->getConversionType()->isBlockPointerType();
+    bool Block2 = Conv2->getConversionType()->isBlockPointerType();
+    if (Block1 != Block2)
+      return Block1? ImplicitConversionSequence::Worse 
+                   : ImplicitConversionSequence::Better;
+  }
+
+  return ImplicitConversionSequence::Indistinguishable;
+}
+  
 /// CompareImplicitConversionSequences - Compare two implicit
 /// conversion sequences to determine whether one is better than the
 /// other or if they are indistinguishable (C++ 13.3.3.2).
@@ -3118,6 +3153,10 @@
       Result = CompareStandardConversionSequences(S,
                                                   ICS1.UserDefined.After,
                                                   ICS2.UserDefined.After);
+    else
+      Result = compareConversionFunctions(S, 
+                                          ICS1.UserDefined.ConversionFunction,
+                                          ICS2.UserDefined.ConversionFunction);
   }
 
   // List-initialization sequence L1 is a better conversion sequence than
@@ -7538,6 +7577,15 @@
   if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
       isa<CXXConversionDecl>(Cand1.Function) &&
       isa<CXXConversionDecl>(Cand2.Function)) {
+    // First check whether we prefer one of the conversion functions over the
+    // other. This only distinguishes the results in non-standard, extension
+    // cases such as the conversion from a lambda closure type to a function
+    // pointer or block.
+    ImplicitConversionSequence::CompareKind FuncResult
+      = compareConversionFunctions(S, Cand1.Function, Cand2.Function);
+    if (FuncResult != ImplicitConversionSequence::Indistinguishable)
+      return FuncResult;
+          
     switch (CompareStandardConversionSequences(S,
                                                Cand1.FinalConversion,
                                                Cand2.FinalConversion)) {

Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm?rev=151170&r1=151169&r2=151170&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm Wed Feb 22 11:32:19 2012
@@ -55,3 +55,34 @@
     }();
   }();
 }
+
+namespace overloading {
+  void bool_conversion() {
+    if ([](){}) {
+    }
+
+    bool b = []{};
+    b = (bool)[]{};
+  }
+
+  void conversions() {
+    int (*fp)(int) = [](int x) { return x + 1; };
+    fp = [](int x) { return x + 1; };
+
+    typedef int (*func_ptr)(int);
+    fp = (func_ptr)[](int x) { return x + 1; };
+
+    int (^bp)(int) = [](int x) { return x + 1; };
+    bp = [](int x) { return x + 1; };
+
+    typedef int (^block_ptr)(int);
+    bp = (block_ptr)[](int x) { return x + 1; };
+  }
+
+  int &accept_lambda_conv(int (*fp)(int));
+  float &accept_lambda_conv(int (^bp)(int));
+
+  void call_with_lambda() {
+    int &ir = accept_lambda_conv([](int x) { return x + 1; });
+  }
+}





More information about the cfe-commits mailing list