summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-22 17:32:19 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-22 17:32:19 +0000
commit2837aa2932710e1e8ef7a75b582284ae401d79f5 (patch)
tree4ff7d2bf64c8be70792886c4f39640adfec44d98 /clang
parent5dfe6dab254decb87a8f798e18bb812eca3ca626 (diff)
downloadbcm5719-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.cpp48
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm31
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; });
+ }
+}
OpenPOWER on IntegriCloud