mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-09 19:03:27 +00:00
Implicitly define a lambda's conversion functions (to function
pointers and block pointers). We use dummy definitions to keep the invariant that an implicit, used definition has a body; IR generation will substitute the actual contents, since they can't be represented as C++. For the block pointer case, compute the copy-initialization needed to capture the lambda object in the block, which IR generation will need later. llvm-svn: 150645
This commit is contained in:
parent
515a60daff
commit
d3b672c385
@ -55,6 +55,7 @@ namespace clang {
|
||||
class CXXABI;
|
||||
// Decls
|
||||
class DeclContext;
|
||||
class CXXConversionDecl;
|
||||
class CXXMethodDecl;
|
||||
class CXXRecordDecl;
|
||||
class Decl;
|
||||
@ -321,6 +322,12 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||
typedef UsuallyTinyPtrVector<const CXXMethodDecl> CXXMethodVector;
|
||||
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods;
|
||||
|
||||
/// \brief Mapping from lambda-to-block-pointer conversion functions to the
|
||||
/// expression used to copy the lambda object.
|
||||
llvm::DenseMap<const CXXConversionDecl *, Expr *> LambdaBlockPointerInits;
|
||||
|
||||
friend class CXXConversionDecl;
|
||||
|
||||
/// \brief Mapping that stores parameterIndex values for ParmVarDecls
|
||||
/// when that value exceeds the bitfield size of
|
||||
/// ParmVarDeclBits.ParameterIndex.
|
||||
|
@ -2180,6 +2180,19 @@ public:
|
||||
return getType()->getAs<FunctionType>()->getResultType();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this conversion function is a conversion from
|
||||
/// a lambda closure type to a block pointer.
|
||||
bool isLambdaToBlockPointerConversion() const;
|
||||
|
||||
/// \brief For an implicit conversion function that converts a lambda
|
||||
/// closure type to a block pointer, retrieve the expression used to
|
||||
/// copy the closure object into the block.
|
||||
Expr *getLambdaToBlockPointerCopyInit() const;
|
||||
|
||||
/// \brief Set the copy-initialization expression to be used when converting
|
||||
/// a lambda object to a block pointer.
|
||||
void setLambdaToBlockPointerCopyInit(Expr *Init);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classof(const CXXConversionDecl *D) { return true; }
|
||||
|
@ -4071,6 +4071,9 @@ let CategoryName = "Lambda Issue" in {
|
||||
"capture of variable '%0' as type %1 calls %select{private|protected}3 "
|
||||
"%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">,
|
||||
AccessControl;
|
||||
def note_lambda_to_block_conv : Note<
|
||||
"implicit capture of lambda object due to conversion to block pointer "
|
||||
"here">;
|
||||
}
|
||||
|
||||
def err_operator_arrow_circular : Error<
|
||||
|
@ -3554,6 +3554,26 @@ public:
|
||||
ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
||||
Scope *CurScope, bool IsInstantiation = false);
|
||||
|
||||
/// \brief Define the "body" of the conversion from a lambda object to a
|
||||
/// function pointer.
|
||||
///
|
||||
/// This routine doesn't actually define a sensible body; rather, it fills
|
||||
/// in the initialization expression needed to copy the lambda object into
|
||||
/// the block, and IR generation actually generates the real body of the
|
||||
/// block pointer conversion.
|
||||
void DefineImplicitLambdaToFunctionPointerConversion(
|
||||
SourceLocation CurrentLoc, CXXConversionDecl *Conv);
|
||||
|
||||
/// \brief Define the "body" of the conversion from a lambda object to a
|
||||
/// block pointer.
|
||||
///
|
||||
/// This routine doesn't actually define a sensible body; rather, it fills
|
||||
/// in the initialization expression needed to copy the lambda object into
|
||||
/// the block, and IR generation actually generates the real body of the
|
||||
/// block pointer conversion.
|
||||
void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc,
|
||||
CXXConversionDecl *Conv);
|
||||
|
||||
// ParseObjCStringLiteral - Parse Objective-C string literals.
|
||||
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
|
||||
Expr **Strings,
|
||||
|
@ -1759,6 +1759,21 @@ CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
||||
EndLocation);
|
||||
}
|
||||
|
||||
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
|
||||
return isImplicit() && getParent()->isLambda() &&
|
||||
getConversionType()->isBlockPointerType();
|
||||
}
|
||||
|
||||
Expr *CXXConversionDecl::getLambdaToBlockPointerCopyInit() const {
|
||||
assert(isLambdaToBlockPointerConversion());
|
||||
return getASTContext().LambdaBlockPointerInits[this];
|
||||
}
|
||||
|
||||
void CXXConversionDecl::setLambdaToBlockPointerCopyInit(Expr *Init) {
|
||||
assert(isLambdaToBlockPointerConversion());
|
||||
getASTContext().LambdaBlockPointerInits[this] = Init;
|
||||
}
|
||||
|
||||
void LinkageSpecDecl::anchor() { }
|
||||
|
||||
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
|
||||
|
@ -9050,7 +9050,60 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
|
||||
(FD->isDefaulted() || FD->isImplicit()) &&
|
||||
isa<CXXMethodDecl>(FD);
|
||||
}
|
||||
|
||||
|
||||
void Sema::DefineImplicitLambdaToFunctionPointerConversion(
|
||||
SourceLocation CurrentLocation,
|
||||
CXXConversionDecl *Conv)
|
||||
{
|
||||
Conv->setUsed();
|
||||
|
||||
ImplicitlyDefinedFunctionScope Scope(*this, Conv);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
// Introduce a bogus body, which IR generation will override anyway.
|
||||
Conv->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
|
||||
Conv->getLocation()));
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(Conv);
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::DefineImplicitLambdaToBlockPointerConversion(
|
||||
SourceLocation CurrentLocation,
|
||||
CXXConversionDecl *Conv)
|
||||
{
|
||||
Conv->setUsed();
|
||||
|
||||
ImplicitlyDefinedFunctionScope Scope(*this, Conv);
|
||||
DiagnosticErrorTrap Trap(Diags);
|
||||
|
||||
// Copy-initialize the lambda object as needed to capture
|
||||
Expr *This = ActOnCXXThis(CurrentLocation).take();
|
||||
Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).take();
|
||||
ExprResult Init = PerformCopyInitialization(
|
||||
InitializedEntity::InitializeBlock(CurrentLocation,
|
||||
DerefThis->getType(),
|
||||
/*NRVO=*/false),
|
||||
CurrentLocation, DerefThis);
|
||||
if (!Init.isInvalid())
|
||||
Init = ActOnFinishFullExpr(Init.take());
|
||||
|
||||
if (!Init.isInvalid())
|
||||
Conv->setLambdaToBlockPointerCopyInit(Init.take());
|
||||
else {
|
||||
Diag(CurrentLocation, diag::note_lambda_to_block_conv);
|
||||
}
|
||||
|
||||
// Introduce a bogus body, which IR generation will override anyway.
|
||||
Conv->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
|
||||
Conv->getLocation()));
|
||||
|
||||
if (ASTMutationListener *L = getASTMutationListener()) {
|
||||
L->CompletedImplicitDefinition(Conv);
|
||||
}
|
||||
}
|
||||
|
||||
ExprResult
|
||||
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
|
||||
CXXConstructorDecl *Constructor,
|
||||
|
@ -9447,6 +9447,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
|
||||
else
|
||||
DefineImplicitMoveAssignment(Loc, MethodDecl);
|
||||
}
|
||||
} else if (isa<CXXConversionDecl>(MethodDecl) &&
|
||||
MethodDecl->getParent()->isLambda()) {
|
||||
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(MethodDecl);
|
||||
if (Conversion->isLambdaToBlockPointerConversion())
|
||||
DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
|
||||
else
|
||||
DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
|
||||
} else if (MethodDecl->isVirtual())
|
||||
MarkVTableUsed(Loc, MethodDecl->getParent());
|
||||
}
|
||||
@ -10041,7 +10048,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
|
||||
}
|
||||
|
||||
SemaRef.MarkAnyDeclReferenced(Loc, D);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Perform reference-marking and odr-use handling for a
|
||||
/// BlockDeclRefExpr.
|
||||
|
@ -1206,6 +1206,8 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
||||
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
|
||||
VisitCXXMethodDecl(D);
|
||||
D->IsExplicitSpecified = Record[Idx++];
|
||||
if (D->isLambdaToBlockPointerConversion())
|
||||
D->setLambdaToBlockPointerCopyInit(Reader.ReadExpr(F));
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
|
||||
|
@ -961,6 +961,8 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
||||
void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
|
||||
VisitCXXMethodDecl(D);
|
||||
Record.push_back(D->IsExplicitSpecified);
|
||||
if (D->isLambdaToBlockPointerConversion())
|
||||
Writer.AddStmt(D->getLambdaToBlockPointerCopyInit());
|
||||
Code = serialization::DECL_CXX_CONVERSION;
|
||||
}
|
||||
|
||||
|
@ -13,3 +13,23 @@ void conversion_to_block(int captured) {
|
||||
const auto lambda = [=](int x) { return x + captured; };
|
||||
int (^b2)(int) = lambda;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class ConstCopyConstructorBoom {
|
||||
public:
|
||||
ConstCopyConstructorBoom(ConstCopyConstructorBoom&);
|
||||
|
||||
ConstCopyConstructorBoom(const ConstCopyConstructorBoom&) {
|
||||
T *ptr = 1; // expected-error{{cannot initialize a variable of type 'float *' with an rvalue of type 'int'}}
|
||||
}
|
||||
|
||||
void foo() const;
|
||||
};
|
||||
|
||||
void conversion_to_block_init(ConstCopyConstructorBoom<int> boom,
|
||||
ConstCopyConstructorBoom<float> boom2) {
|
||||
const auto& lambda1([=] { boom.foo(); }); // okay
|
||||
|
||||
const auto& lambda2([=] { boom2.foo(); }); // expected-note{{in instantiation of member function}}
|
||||
void (^block)(void) = lambda2;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
|
||||
// RUN: %clang_cc1 -ast-print -pedantic-errors -std=c++11 -include-pch %t-cxx11 %s | FileCheck -check-prefix=CHECK-PRINT %s
|
||||
// RUN: %clang_cc1 -pedantic-errors -fblocks -std=c++11 -emit-pch %s -o %t-cxx11
|
||||
// RUN: %clang_cc1 -ast-print -pedantic-errors -fblocks -std=c++11 -include-pch %t-cxx11 %s | FileCheck -check-prefix=CHECK-PRINT %s
|
||||
|
||||
#ifndef HEADER_INCLUDED
|
||||
|
||||
@ -26,6 +26,13 @@ inline int sum_array(int n) {
|
||||
|
||||
return lambda(n);
|
||||
}
|
||||
|
||||
inline int to_block_pointer(int n) {
|
||||
auto lambda = [=](int m) { return n + m; };
|
||||
int (^block)(int) = lambda;
|
||||
return block(17);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// CHECK-PRINT: T add_slowly
|
||||
@ -33,7 +40,7 @@ inline int sum_array(int n) {
|
||||
template float add_slowly(const float&, const float&);
|
||||
|
||||
int add(int x, int y) {
|
||||
return add_int_slowly_twice(x, y) + sum_array(4);
|
||||
return add_int_slowly_twice(x, y) + sum_array(4) + to_block_pointer(5);
|
||||
}
|
||||
|
||||
// CHECK-PRINT: inline int add_int_slowly_twice
|
||||
|
Loading…
x
Reference in New Issue
Block a user