From b734e2437d3c4b20a28b448e75cb45ef71f0b518 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 22 Feb 2012 17:32:19 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151170 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaOverload.cpp | 48 +++++++++++++++++++ .../expr/expr.prim/expr.prim.lambda/blocks.mm | 31 ++++++++++++ 2 files changed, 79 insertions(+) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index e5db60b200..2b567b3984 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3065,6 +3065,41 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { 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(Function1); + if (!Conv1) + return ImplicitConversionSequence::Indistinguishable; + + CXXConversionDecl *Conv2 = dyn_cast(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 @@ CompareImplicitConversionSequences(Sema &S, 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 @@ isBetterOverloadCandidate(Sema &S, if (UserDefinedConversion && Cand1.Function && Cand2.Function && isa(Cand1.Function) && isa(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)) { diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm index f6a8db23e9..0c3fdb2d80 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm @@ -55,3 +55,34 @@ void nesting() { }(); }(); } + +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; }); + } +} -- 2.40.0