[cfe-commits] r150645 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/DeclCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriterDecl.cpp test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp test/PCH/cxx11-lambdas.cpp
Douglas Gregor
dgregor at apple.com
Wed Feb 15 17:06:17 PST 2012
Author: dgregor
Date: Wed Feb 15 19:06:16 2012
New Revision: 150645
URL: http://llvm.org/viewvc/llvm-project?rev=150645&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp
cfe/trunk/test/PCH/cxx11-lambdas.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed Feb 15 19:06:16 2012
@@ -55,6 +55,7 @@
class CXXABI;
// Decls
class DeclContext;
+ class CXXConversionDecl;
class CXXMethodDecl;
class CXXRecordDecl;
class Decl;
@@ -321,6 +322,12 @@
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.
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Feb 15 19:06:16 2012
@@ -2180,6 +2180,19 @@
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; }
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb 15 19:06:16 2012
@@ -4071,6 +4071,9 @@
"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<
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Feb 15 19:06:16 2012
@@ -3554,6 +3554,26 @@
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,
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Feb 15 19:06:16 2012
@@ -1759,6 +1759,21 @@
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,
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Feb 15 19:06:16 2012
@@ -9050,7 +9050,60 @@
(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,
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 15 19:06:16 2012
@@ -9447,6 +9447,13 @@
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 @@
}
SemaRef.MarkAnyDeclReferenced(Loc, D);
-}
+}
/// \brief Perform reference-marking and odr-use handling for a
/// BlockDeclRefExpr.
Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Feb 15 19:06:16 2012
@@ -1206,6 +1206,8 @@
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
VisitCXXMethodDecl(D);
D->IsExplicitSpecified = Record[Idx++];
+ if (D->isLambdaToBlockPointerConversion())
+ D->setLambdaToBlockPointerCopyInit(Reader.ReadExpr(F));
}
void ASTDeclReader::VisitImportDecl(ImportDecl *D) {
Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Feb 15 19:06:16 2012
@@ -961,6 +961,8 @@
void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
VisitCXXMethodDecl(D);
Record.push_back(D->IsExplicitSpecified);
+ if (D->isLambdaToBlockPointerConversion())
+ Writer.AddStmt(D->getLambdaToBlockPointerCopyInit());
Code = serialization::DECL_CXX_CONVERSION;
}
Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.cpp Wed Feb 15 19:06:16 2012
@@ -13,3 +13,23 @@
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;
+}
Modified: cfe/trunk/test/PCH/cxx11-lambdas.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx11-lambdas.cpp?rev=150645&r1=150644&r2=150645&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx11-lambdas.cpp (original)
+++ cfe/trunk/test/PCH/cxx11-lambdas.cpp Wed Feb 15 19:06:16 2012
@@ -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 @@
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 @@
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
More information about the cfe-commits
mailing list