diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-22 17:32:19 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-22 17:32:19 +0000 |
commit | 2837aa2932710e1e8ef7a75b582284ae401d79f5 (patch) | |
tree | 4ff7d2bf64c8be70792886c4f39640adfec44d98 /clang | |
parent | 5dfe6dab254decb87a8f798e18bb812eca3ca626 (diff) | |
download | bcm5719-llvm-2837aa2932710e1e8ef7a75b582284ae401d79f5.tar.gz bcm5719-llvm-2837aa2932710e1e8ef7a75b582284ae401d79f5.zip |
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.
llvm-svn: 151170
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 48 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm | 31 |
2 files changed, 79 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index e5db60b2002..2b567b39842 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/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<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 @@ 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<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)) { diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm index f6a8db23e9b..0c3fdb2d80e 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm +++ b/clang/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; }); + } +} |