Template instantiation for Objective-C++ @synchronized statements.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102134 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 4e460f4..c7bb3c8 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1583,7 +1583,8 @@
// Make sure the expression type is an ObjC pointer or "void *".
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
- if (!SyncExpr->getType()->isObjCObjectPointerType()) {
+ if (!SyncExpr->getType()->isDependentType() &&
+ !SyncExpr->getType()->isObjCObjectPointerType()) {
const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
if (!PT || !PT->getPointeeType()->isVoidType())
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index db44a36..9d7f936 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -890,7 +890,7 @@
RParenLoc, MSAsm);
}
- /// \brief Build a new Objective-C throw statement.
+ /// \brief Build a new Objective-C @throw statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
@@ -899,6 +899,18 @@
return getSema().BuildObjCAtThrowStmt(AtLoc, move(Operand));
}
+ /// \brief Build a new Objective-C @synchronized statement.
+ ///
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningStmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc,
+ ExprArg Object,
+ StmtArg Body) {
+ return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, move(Object),
+ move(Body));
+ }
+
/// \brief Build a new C++ exception declaration.
///
/// By default, performs semantic analysis to build the new decaration.
@@ -3676,9 +3688,25 @@
Sema::OwningStmtResult
TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
ObjCAtSynchronizedStmt *S) {
- // FIXME: Implement this
- assert(false && "Cannot transform an Objective-C @synchronized statement");
- return SemaRef.Owned(S->Retain());
+ // Transform the object we are locking.
+ OwningExprResult Object = getDerived().TransformExpr(S->getSynchExpr());
+ if (Object.isInvalid())
+ return SemaRef.StmtError();
+
+ // Transform the body.
+ OwningStmtResult Body = getDerived().TransformStmt(S->getSynchBody());
+ if (Body.isInvalid())
+ return SemaRef.StmtError();
+
+ // If nothing change, just retain the current statement.
+ if (!getDerived().AlwaysRebuild() &&
+ Object.get() == S->getSynchExpr() &&
+ Body.get() == S->getSynchBody())
+ return SemaRef.Owned(S->Retain());
+
+ // Build a new statement.
+ return getDerived().RebuildObjCAtSynchronizedStmt(S->getAtSynchronizedLoc(),
+ move(Object), move(Body));
}
template<typename Derived>
diff --git a/test/SemaObjCXX/instantiate-stmt.mm b/test/SemaObjCXX/instantiate-stmt.mm
index 4c477aa..3d5c86f 100644
--- a/test/SemaObjCXX/instantiate-stmt.mm
+++ b/test/SemaObjCXX/instantiate-stmt.mm
@@ -12,4 +12,13 @@
template void throw_test(NSException *);
template void throw_test(int); // expected-note{{in instantiation of}}
+// @synchronized
+template<typename T>
+void synchronized_test(T value) {
+ @synchronized (value) { // expected-error{{@synchronized requires an Objective-C object type ('int' invalid)}}
+ value = 0;
+ }
+}
+template void synchronized_test(NSException *);
+template void synchronized_test(int); // expected-note{{in instantiation of}}