summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-22 05:02:47 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-22 05:02:47 +0000
commited90df38004678cf1ebf1caa3fbac8a0047be73e (patch)
tree49750c16f2a1c4babf5601c2fe1be8f433583542
parent7cd4a9ba48c08d3804316815c0b5250d4b0bbbe7 (diff)
downloadbcm5719-llvm-ed90df38004678cf1ebf1caa3fbac8a0047be73e.tar.gz
bcm5719-llvm-ed90df38004678cf1ebf1caa3fbac8a0047be73e.zip
Generate an AST for the conversion from a lambda closure type to a
block pointer that returns a block literal which captures (by copy) the lambda closure itself. Some aspects of the block literal are left unspecified, namely the capture variable (which doesn't actually exist) and the body (which will be filled in by IRgen because it can't be written as an AST). Because we're switching to this model, this patch also eliminates tracking the copy-initialization expression for the block capture of the conversion function, since that information is now embedded in the synthesized block literal. -1 side tables FTW. llvm-svn: 151131
-rw-r--r--clang/include/clang/AST/ASTContext.h6
-rw-r--r--clang/include/clang/AST/DeclCXX.h9
-rw-r--r--clang/include/clang/AST/OperationKinds.h9
-rw-r--r--clang/lib/AST/DeclCXX.cpp10
-rw-r--r--clang/lib/AST/Expr.cpp7
-rw-r--r--clang/lib/AST/ExprConstant.cpp2
-rw-r--r--clang/lib/AST/StmtDumper.cpp3
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp3
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprComplex.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp4
-rw-r--r--clang/lib/Sema/SemaChecking.cpp8
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp89
-rw-r--r--clang/lib/Sema/SemaLambda.cpp2
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp2
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp1
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm (renamed from clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp)0
-rw-r--r--clang/test/PCH/cxx11-lambdas.mm (renamed from clang/test/PCH/cxx11-lambdas.cpp)0
20 files changed, 114 insertions, 46 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 10fc81ab22b..26e91959624 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -323,12 +323,6 @@ class ASTContext : public 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 from each declaration context to its corresponding lambda
/// mangling context.
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 45bb647a65d..afb53757459 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -2261,15 +2261,6 @@ public:
/// 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; }
diff --git a/clang/include/clang/AST/OperationKinds.h b/clang/include/clang/AST/OperationKinds.h
index 8cf79b2bfa8..258637d7f9b 100644
--- a/clang/include/clang/AST/OperationKinds.h
+++ b/clang/include/clang/AST/OperationKinds.h
@@ -281,7 +281,14 @@ enum CastKind {
/// \brief Converts from _Atomic(T) to T.
CK_AtomicToNonAtomic,
/// \brief Converts from T to _Atomic(T).
- CK_NonAtomicToAtomic
+ CK_NonAtomicToAtomic,
+
+ /// \brief Causes a block literal to by copied to the heap and then
+ /// autoreleased.
+ ///
+ /// This particular cast kind is used for the conversion from a C++11
+ /// lambda expression to a block pointer.
+ CK_CopyAndAutoreleaseBlockObject
};
#define CK_Invalid ((CastKind) -1)
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 9840cc7820f..4dd44cbf179 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1770,16 +1770,6 @@ bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
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,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 75c450867b5..f95ca173067 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1076,6 +1076,11 @@ void CastExpr::CheckCastConsistency() const {
!getSubExpr()->getType()->isBlockPointerType());
goto CheckNoBasePath;
+ case CK_CopyAndAutoreleaseBlockObject:
+ assert(getType()->isBlockPointerType());
+ assert(getSubExpr()->getType()->isBlockPointerType());
+ goto CheckNoBasePath;
+
// These should not have an inheritance path.
case CK_Dynamic:
case CK_ToUnion:
@@ -1231,6 +1236,8 @@ const char *CastExpr::getCastKindName() const {
return "AtomicToNonAtomic";
case CK_NonAtomicToAtomic:
return "NonAtomicToAtomic";
+ case CK_CopyAndAutoreleaseBlockObject:
+ return "CopyAndAutoreleaseBlockObject";
}
llvm_unreachable("Unhandled cast kind!");
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 5420876866d..ed64153f853 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5209,6 +5209,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
return Error(E);
case CK_UserDefinedConversion:
@@ -5684,6 +5685,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp
index 90a8fb611a7..608e8ae46e5 100644
--- a/clang/lib/AST/StmtDumper.cpp
+++ b/clang/lib/AST/StmtDumper.cpp
@@ -516,7 +516,8 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
OS << "(capture ";
if (i->isByRef()) OS << "byref ";
if (i->isNested()) OS << "nested ";
- DumpDeclRef(i->getVariable());
+ if (i->getVariable())
+ DumpDeclRef(i->getVariable());
if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
OS << ")";
}
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 060841d5078..18aa0fc4317 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2096,7 +2096,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_ARCProduceObject:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
- case CK_ARCExtendBlockObject: {
+ case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject: {
// These casts only produce lvalues when we're binding a reference to a
// temporary realized from a (converted) pure rvalue. Emit the expression
// as a value, copy it into a temporary, and return an lvalue referring to
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index afe70a5dda8..5fb334bd8e8 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -614,6 +614,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index 15fa225eb85..ae192cb8365 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -413,6 +413,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index a7cd36862ba..4fc21fe708f 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -636,6 +636,7 @@ public:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
return 0;
// These don't need to be handled here because Evaluate knows how to
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 6eed2ed346f..76c91a5ff37 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1148,6 +1148,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_ARCExtendBlockObject:
return CGF.EmitARCExtendBlockObject(E);
+ case CK_CopyAndAutoreleaseBlockObject:
+ CGF.ErrorUnsupported(E, "copy/autorelease block object");
+ return 0;
+
case CK_FloatingRealToComplex:
case CK_FloatingComplexCast:
case CK_IntegralRealToComplex:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9454a751550..7f42b2059d7 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3000,9 +3000,11 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars) {
Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
QualType T = SubExpr->getType();
- if (SubExpr->getType()->isPointerType() ||
- SubExpr->getType()->isBlockPointerType() ||
- SubExpr->getType()->isObjCQualifiedIdType())
+ if (cast<CastExpr>(E)->getCastKind() == CK_CopyAndAutoreleaseBlockObject)
+ return 0;
+ else if (SubExpr->getType()->isPointerType() ||
+ SubExpr->getType()->isBlockPointerType() ||
+ SubExpr->getType()->isObjCQualifiedIdType())
return EvalAddr(SubExpr, refVars);
else if (T->isArrayType())
return EvalVal(SubExpr, refVars);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index a1a952b833f..22fb8cb7a83 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -8755,9 +8755,9 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
/// \brief Mark the call operator of the given lambda closure type as "used".
static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
CXXMethodDecl *CallOperator
- = cast<CXXMethodDecl>(
- *Lambda->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ = cast<CXXMethodDecl>(
+ *Lambda->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
CallOperator->setReferenced();
CallOperator->setUsed();
}
@@ -8805,14 +8805,21 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
SourceLocation CurrentLocation,
CXXConversionDecl *Conv)
{
+ CXXRecordDecl *Lambda = Conv->getParent();
+
// Make sure that the lambda call operator is marked used.
- markLambdaCallOperatorUsed(*this, Conv->getParent());
+ CXXMethodDecl *CallOperator
+ = cast<CXXMethodDecl>(
+ *Lambda->lookup(
+ Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ CallOperator->setReferenced();
+ CallOperator->setUsed();
Conv->setUsed();
ImplicitlyDefinedFunctionScope Scope(*this, Conv);
DiagnosticErrorTrap Trap(Diags);
- // Copy-initialize the lambda object as needed to capture
+ // Copy-initialize the lambda object as needed to capture it.
Expr *This = ActOnCXXThis(CurrentLocation).take();
Expr *DerefThis =CreateBuiltinUnaryOp(CurrentLocation, UO_Deref, This).take();
ExprResult Init = PerformCopyInitialization(
@@ -8823,16 +8830,78 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
if (!Init.isInvalid())
Init = ActOnFinishFullExpr(Init.take());
- if (!Init.isInvalid())
- Conv->setLambdaToBlockPointerCopyInit(Init.take());
- else {
+ if (Init.isInvalid()) {
Diag(CurrentLocation, diag::note_lambda_to_block_conv);
+ Conv->setInvalidDecl();
+ return;
}
- // Introduce a bogus body, which IR generation will override anyway.
- Conv->setBody(new (Context) CompoundStmt(Context, 0, 0, Conv->getLocation(),
+ // Create the new block to be returned.
+ BlockDecl *Block = BlockDecl::Create(Context, Conv, Conv->getLocation());
+
+ // Set the type information.
+ Block->setSignatureAsWritten(CallOperator->getTypeSourceInfo());
+ Block->setIsVariadic(CallOperator->isVariadic());
+ Block->setBlockMissingReturnType(false);
+
+ // Add parameters.
+ SmallVector<ParmVarDecl *, 4> BlockParams;
+ for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
+ ParmVarDecl *From = CallOperator->getParamDecl(I);
+ BlockParams.push_back(ParmVarDecl::Create(Context, Block,
+ From->getLocStart(),
+ From->getLocation(),
+ From->getIdentifier(),
+ From->getType(),
+ From->getTypeSourceInfo(),
+ From->getStorageClass(),
+ From->getStorageClassAsWritten(),
+ /*DefaultArg=*/0));
+ }
+ Block->setParams(BlockParams);
+
+ // Add capture. The capture is uses a fake (NULL) variable, since we don't
+ // actually want to have to name a capture variable. However, the
+ // initializer copy-initializes the lambda object.
+ BlockDecl::Capture Capture(/*Variable=*/0, /*ByRef=*/false, /*Nested=*/false,
+ /*Copy=*/Init.take());
+ Block->setCaptures(Context, &Capture, &Capture + 1,
+ /*CapturesCXXThis=*/false);
+
+ // Add a fake function body to the block. IR generation is responsible
+ // for filling in the actual body, which cannot be expressed as an AST.
+ Block->setBody(new (Context) CompoundStmt(Context, 0, 0,
+ Conv->getLocation(),
+ Conv->getLocation()));
+
+ // Create the block literal expression.
+ Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
+ ExprCleanupObjects.push_back(Block);
+ ExprNeedsCleanups = true;
+
+ // If we're not under ARC, make sure we still get the _Block_copy/autorelease
+ // behavior.
+ if (!getLangOptions().ObjCAutoRefCount)
+ BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock->getType(),
+ CK_CopyAndAutoreleaseBlockObject,
+ BuildBlock, 0, VK_RValue);
+
+ // Create the return statement that returns the block from the conversion
+ // function.
+ StmtResult Return = ActOnReturnStmt(Conv->getLocation(), BuildBlock);
+ if (Return.isInvalid()) {
+ Diag(CurrentLocation, diag::note_lambda_to_block_conv);
+ Conv->setInvalidDecl();
+ return;
+ }
+
+ // Set the body of the conversion function.
+ Stmt *ReturnS = Return.take();
+ Conv->setBody(new (Context) CompoundStmt(Context, &ReturnS, 1,
+ Conv->getLocation(),
Conv->getLocation()));
+ // We're done; notify the mutation listener, if any.
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Conv);
}
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 016322fe523..b0c6a61bce9 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -643,7 +643,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// non-explicit const conversion function to a block pointer having the
// same parameter and return types as the closure type's function call
// operator.
- if (getLangOptions().Blocks)
+ if (getLangOptions().Blocks && getLangOptions().ObjC1)
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index fe09cdafa7c..ce92e9cab49 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1213,8 +1213,6 @@ 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) {
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index f57a166d7ca..26ee8b5f2af 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -965,8 +965,6 @@ 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;
}
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 3e1b6b0aec6..e06e71699f2 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -218,6 +218,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject: // Fall-through.
+ case CK_CopyAndAutoreleaseBlockObject:
// The analyser can ignore atomic casts for now, although some future
// checkers may want to make certain that you're not modifying the same
// value through atomic and nonatomic pointers.
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm
index f6a8db23e9b..f6a8db23e9b 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm
diff --git a/clang/test/PCH/cxx11-lambdas.cpp b/clang/test/PCH/cxx11-lambdas.mm
index c00ec638075..c00ec638075 100644
--- a/clang/test/PCH/cxx11-lambdas.cpp
+++ b/clang/test/PCH/cxx11-lambdas.mm
OpenPOWER on IntegriCloud