aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Expr.h8
-rw-r--r--lib/AST/Expr.cpp12
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp11
-rw-r--r--lib/Sema/TreeTransform.h38
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp39
5 files changed, 89 insertions, 19 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 3bcbf3661a..46fda21fc0 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -3572,15 +3572,9 @@ class BlockDeclRefExpr : public Expr {
bool ConstQualAdded : 1;
Stmt *CopyConstructorVal;
public:
- // FIXME: Fix type/value dependence!
- // FIXME: Variadic templates.
BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
SourceLocation l, bool ByRef, bool constAdded = false,
- Stmt *copyConstructorVal = 0)
- : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary,
- (!t.isNull() && t->isDependentType()), false, false),
- D(d), Loc(l), IsByRef(ByRef),
- ConstQualAdded(constAdded), CopyConstructorVal(copyConstructorVal) {}
+ Stmt *copyConstructorVal = 0);
// \brief Build an empty reference to a declared variable in a
// block.
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 4afed433a3..9dc790256e 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2932,6 +2932,18 @@ Stmt::child_iterator ObjCMessageExpr::child_end() {
}
// Blocks
+BlockDeclRefExpr::BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK,
+ SourceLocation l, bool ByRef,
+ bool constAdded, Stmt *copyConstructorVal)
+ : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary,
+ (!t.isNull() && t->isDependentType()), false,
+ d->isParameterPack()),
+ D(d), Loc(l), IsByRef(ByRef),
+ ConstQualAdded(constAdded), CopyConstructorVal(copyConstructorVal)
+{
+ // FIXME: Compute type/value dependence.
+}
+
Stmt::child_iterator BlockExpr::child_begin() { return child_iterator(); }
Stmt::child_iterator BlockExpr::child_end() { return child_iterator(); }
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 38a777efb1..3f76d9f6e3 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -64,7 +64,7 @@ namespace {
return true;
}
- /// \brief Record occurrences of (FIXME: function and) non-type template
+ /// \brief Record occurrences of function and non-type template
/// parameter packs in an expression.
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (E->getDecl()->isParameterPack())
@@ -73,6 +73,15 @@ namespace {
return true;
}
+ // \brief Record occurrences of function and non-type template parameter
+ // packs in a block-captured expression.
+ bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+ if (E->getDecl()->isParameterPack())
+ Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation()));
+
+ return true;
+ }
+
/// \brief Record occurrences of template template parameter packs.
bool TraverseTemplateName(TemplateName Template) {
if (TemplateTemplateParmDecl *TTP
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ebc34d0f35..1cb24e70bf 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -7122,16 +7122,13 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
llvm::SmallVector<QualType, 4> ParamTypes;
// Parameter substitution.
- // FIXME: Variadic templates
- const BlockDecl *BD = E->getBlockDecl();
- for (BlockDecl::param_const_iterator P = BD->param_begin(),
- EN = BD->param_end(); P != EN; ++P) {
- ParmVarDecl *OldParm = (*P);
- ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm,
- llvm::Optional<unsigned>());
- Params.push_back(NewParm);
- ParamTypes.push_back(NewParm->getType());
- }
+ BlockDecl *BD = E->getBlockDecl();
+ if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
+ BD->param_begin(),
+ BD->param_size(), 0, ParamTypes,
+ &Params))
+ return true;
+
const FunctionType *BExprFunctionType = E->getFunctionType();
QualType BExprResultType = BExprFunctionType->getResultType();
@@ -7141,6 +7138,19 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
else if (BExprResultType != SemaRef.Context.DependentTy)
CurBlock->ReturnType = getDerived().TransformType(BExprResultType);
}
+
+ // If the return type has not been determined yet, leave it as a dependent
+ // type; it'll get set when we process the body.
+ if (CurBlock->ReturnType.isNull())
+ CurBlock->ReturnType = getSema().Context.DependentTy;
+
+ // Don't allow returning a objc interface by value.
+ if (CurBlock->ReturnType->isObjCObjectType()) {
+ getSema().Diag(E->getLocStart(),
+ diag::err_object_cannot_be_passed_returned_by_value)
+ << 0 << CurBlock->ReturnType;
+ return ExprError();
+ }
QualType FunctionType = getDerived().RebuildFunctionProtoType(
CurBlock->ReturnType,
@@ -7154,7 +7164,13 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
// Set the parameters on the block decl.
if (!Params.empty())
CurBlock->TheDecl->setParams(Params.data(), Params.size());
-
+
+ // If the return type wasn't explicitly set, it will have been marked as a
+ // dependent type (DependentTy); clear out the return type setting so
+ // we will deduce the return type when type-checking the block's body.
+ if (CurBlock->ReturnType == getSema().Context.DependentTy)
+ CurBlock->ReturnType = QualType();
+
// Transform the body
StmtResult Body = getDerived().TransformStmt(E->getBody());
if (Body.isInvalid())
diff --git a/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp b/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
new file mode 100644
index 0000000000..62cf4298f7
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.variadic/ext-blocks.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s
+
+// Tests the use of blocks with variadic templates.
+template<typename ...Args>
+int f0(Args ...args) {
+ return ^ {
+ return sizeof...(Args);
+ }() + ^ {
+ return sizeof...(args);
+ }();
+}
+
+template<typename ...Args>
+int f1(Args ...args) {
+ return ^ {
+ return f0(args...);
+ }();
+}
+
+template int f0(int, float, double);
+template int f1(const char*, int, float, double);
+
+template<typename ...Args>
+int f2(Args ...args) {
+ return ^(Args ...block_args) {
+ return f1(block_args...);
+ }(args + 0 ...);
+}
+
+template int f2(const char*, int, float, double);
+
+template<typename ...Args>
+int f3(Args ...args) {
+ return ^(Args *...block_args) {
+ return f1(block_args...);
+ }(&args...);
+}
+
+template int f3(const char*, int, float, double);