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
This commit is contained in:
parent
5dfe6dab25
commit
2837aa2932
|
@ -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)) {
|
||||
|
|
|
@ -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; });
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue