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;
/// 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; }
/// \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)
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,
!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:
return "AtomicToNonAtomic";
case CK_NonAtomicToAtomic:
return "NonAtomicToAtomic";
+ case CK_CopyAndAutoreleaseBlockObject:
+ return "CopyAndAutoreleaseBlockObject";
}
llvm_unreachable("Unhandled cast kind!");
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
return Error(E);
case CK_UserDefinedConversion:
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
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 << ")";
}
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
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_CopyAndAutoreleaseBlockObject:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
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
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:
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);
/// \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();
}
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(
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);
}
// 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.
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
VisitCXXMethodDecl(D);
D->IsExplicitSpecified = Record[Idx++];
- if (D->isLambdaToBlockPointerConversion())
- D->setLambdaToBlockPointerCopyInit(Reader.ReadExpr(F));
}
void ASTDeclReader::VisitImportDecl(ImportDecl *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;
}
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.