Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 0752403

Browse files
committed
The lock operand to an @synchronized statement is also
supposed to be a full-expression; make it so. In ARC, make sure we retain the lock for the entire protected block. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136271 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a2ee20a commit 0752403

File tree

6 files changed

+106
-47
lines changed

6 files changed

+106
-47
lines changed

include/clang/Sema/Sema.h

+2
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,8 @@ class Sema {
21012101
StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw);
21022102
StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,
21032103
Scope *CurScope);
2104+
ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc,
2105+
Expr *operand);
21042106
StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
21052107
Expr *SynchExpr,
21062108
Stmt *SynchBody);

lib/CodeGen/CGObjCRuntime.cpp

+15-10
Original file line numberDiff line numberDiff line change
@@ -288,21 +288,26 @@ void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF,
288288
const ObjCAtSynchronizedStmt &S,
289289
llvm::Function *syncEnterFn,
290290
llvm::Function *syncExitFn) {
291-
// Evaluate the lock operand. This should dominate the cleanup.
292-
llvm::Value *SyncArg =
293-
CGF.EmitScalarExpr(S.getSynchExpr());
291+
CodeGenFunction::RunCleanupsScope cleanups(CGF);
292+
293+
// Evaluate the lock operand. This is guaranteed to dominate the
294+
// ARC release and lock-release cleanups.
295+
const Expr *lockExpr = S.getSynchExpr();
296+
llvm::Value *lock;
297+
if (CGF.getLangOptions().ObjCAutoRefCount) {
298+
lock = CGF.EmitARCRetainScalarExpr(lockExpr);
299+
lock = CGF.EmitObjCConsumeObject(lockExpr->getType(), lock);
300+
} else {
301+
lock = CGF.EmitScalarExpr(lockExpr);
302+
}
303+
lock = CGF.Builder.CreateBitCast(lock, CGF.VoidPtrTy);
294304

295305
// Acquire the lock.
296-
SyncArg = CGF.Builder.CreateBitCast(SyncArg, syncEnterFn->getFunctionType()->getParamType(0));
297-
CGF.Builder.CreateCall(syncEnterFn, SyncArg);
306+
CGF.Builder.CreateCall(syncEnterFn, lock)->setDoesNotThrow();
298307

299308
// Register an all-paths cleanup to release the lock.
300-
CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn,
301-
SyncArg);
309+
CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, lock);
302310

303311
// Emit the body of the statement.
304312
CGF.EmitStmt(S.getSynchBody());
305-
306-
// Pop the lock-release cleanup.
307-
CGF.PopCleanupBlock();
308313
}

lib/Parse/ParseObjc.cpp

+33-18
Original file line numberDiff line numberDiff line change
@@ -1560,31 +1560,46 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
15601560
Diag(Tok, diag::err_expected_lparen_after) << "@synchronized";
15611561
return StmtError();
15621562
}
1563+
1564+
// The operand is surrounded with parentheses.
15631565
ConsumeParen(); // '('
1564-
ExprResult Res(ParseExpression());
1565-
if (Res.isInvalid()) {
1566-
SkipUntil(tok::semi);
1567-
return StmtError();
1568-
}
1569-
if (Tok.isNot(tok::r_paren)) {
1570-
Diag(Tok, diag::err_expected_lbrace);
1571-
return StmtError();
1566+
ExprResult operand(ParseExpression());
1567+
1568+
if (Tok.is(tok::r_paren)) {
1569+
ConsumeParen(); // ')'
1570+
} else {
1571+
if (!operand.isInvalid())
1572+
Diag(Tok, diag::err_expected_rparen);
1573+
1574+
// Skip forward until we see a left brace, but don't consume it.
1575+
SkipUntil(tok::l_brace, true, true);
15721576
}
1573-
ConsumeParen(); // ')'
1577+
1578+
// Require a compound statement.
15741579
if (Tok.isNot(tok::l_brace)) {
1575-
Diag(Tok, diag::err_expected_lbrace);
1580+
if (!operand.isInvalid())
1581+
Diag(Tok, diag::err_expected_lbrace);
15761582
return StmtError();
15771583
}
1578-
// Enter a scope to hold everything within the compound stmt. Compound
1579-
// statements can always hold declarations.
1580-
ParseScope BodyScope(this, Scope::DeclScope);
15811584

1582-
StmtResult SynchBody(ParseCompoundStatementBody());
1585+
// Check the @synchronized operand now.
1586+
if (!operand.isInvalid())
1587+
operand = Actions.ActOnObjCAtSynchronizedOperand(atLoc, operand.take());
15831588

1584-
BodyScope.Exit();
1585-
if (SynchBody.isInvalid())
1586-
SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
1587-
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.take(), SynchBody.take());
1589+
// Parse the compound statement within a new scope.
1590+
ParseScope bodyScope(this, Scope::DeclScope);
1591+
StmtResult body(ParseCompoundStatementBody());
1592+
bodyScope.Exit();
1593+
1594+
// If there was a semantic or parse error earlier with the
1595+
// operand, fail now.
1596+
if (operand.isInvalid())
1597+
return StmtError();
1598+
1599+
if (body.isInvalid())
1600+
body = Actions.ActOnNullStmt(Tok.getLocation());
1601+
1602+
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, operand.get(), body.get());
15881603
}
15891604

15901605
/// objc-try-catch-statement:

lib/Sema/SemaStmt.cpp

+22-15
Original file line numberDiff line numberDiff line change
@@ -2232,25 +2232,32 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw,
22322232
return BuildObjCAtThrowStmt(AtLoc, Throw);
22332233
}
22342234

2235-
StmtResult
2236-
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
2237-
Stmt *SyncBody) {
2238-
getCurFunction()->setHasBranchProtectedScope();
2239-
2240-
ExprResult Result = DefaultLvalueConversion(SyncExpr);
2241-
if (Result.isInvalid())
2242-
return StmtError();
2235+
ExprResult
2236+
Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) {
2237+
ExprResult result = DefaultLvalueConversion(operand);
2238+
if (result.isInvalid())
2239+
return ExprError();
2240+
operand = result.take();
22432241

2244-
SyncExpr = Result.take();
22452242
// Make sure the expression type is an ObjC pointer or "void *".
2246-
if (!SyncExpr->getType()->isDependentType() &&
2247-
!SyncExpr->getType()->isObjCObjectPointerType()) {
2248-
const PointerType *PT = SyncExpr->getType()->getAs<PointerType>();
2249-
if (!PT || !PT->getPointeeType()->isVoidType())
2250-
return StmtError(Diag(AtLoc, diag::error_objc_synchronized_expects_object)
2251-
<< SyncExpr->getType() << SyncExpr->getSourceRange());
2243+
QualType type = operand->getType();
2244+
if (!type->isDependentType() &&
2245+
!type->isObjCObjectPointerType()) {
2246+
const PointerType *pointerType = type->getAs<PointerType>();
2247+
if (!pointerType || !pointerType->getPointeeType()->isVoidType())
2248+
return Diag(atLoc, diag::error_objc_synchronized_expects_object)
2249+
<< type << operand->getSourceRange();
22522250
}
22532251

2252+
// The operand to @synchronized is a full-expression.
2253+
return MaybeCreateExprWithCleanups(operand);
2254+
}
2255+
2256+
StmtResult
2257+
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr,
2258+
Stmt *SyncBody) {
2259+
// We can't jump into or indirect-jump out of a @synchronized block.
2260+
getCurFunction()->setHasBranchProtectedScope();
22542261
return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody));
22552262
}
22562263

lib/Sema/TreeTransform.h

+16-4
Original file line numberDiff line numberDiff line change
@@ -1181,15 +1181,22 @@ class TreeTransform {
11811181
return getSema().BuildObjCAtThrowStmt(AtLoc, Operand);
11821182
}
11831183

1184+
/// \brief Rebuild the operand to an Objective-C @synchronized statement.
1185+
///
1186+
/// By default, performs semantic analysis to build the new statement.
1187+
/// Subclasses may override this routine to provide different behavior.
1188+
ExprResult RebuildObjCAtSynchronizedOperand(SourceLocation atLoc,
1189+
Expr *object) {
1190+
return getSema().ActOnObjCAtSynchronizedOperand(atLoc, object);
1191+
}
1192+
11841193
/// \brief Build a new Objective-C @synchronized statement.
11851194
///
11861195
/// By default, performs semantic analysis to build the new statement.
11871196
/// Subclasses may override this routine to provide different behavior.
11881197
StmtResult RebuildObjCAtSynchronizedStmt(SourceLocation AtLoc,
1189-
Expr *Object,
1190-
Stmt *Body) {
1191-
return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object,
1192-
Body);
1198+
Expr *Object, Stmt *Body) {
1199+
return getSema().ActOnObjCAtSynchronizedStmt(AtLoc, Object, Body);
11931200
}
11941201

11951202
/// \brief Build a new Objective-C @autoreleasepool statement.
@@ -5479,6 +5486,11 @@ TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
54795486
ExprResult Object = getDerived().TransformExpr(S->getSynchExpr());
54805487
if (Object.isInvalid())
54815488
return StmtError();
5489+
Object =
5490+
getDerived().RebuildObjCAtSynchronizedOperand(S->getAtSynchronizedLoc(),
5491+
Object.get());
5492+
if (Object.isInvalid())
5493+
return StmtError();
54825494

54835495
// Transform the body.
54845496
StmtResult Body = getDerived().TransformStmt(S->getSynchBody());

test/CodeGenObjC/arc.m

+18
Original file line numberDiff line numberDiff line change
@@ -1666,3 +1666,21 @@ void test58b(void) {
16661666
__attribute__((objc_precise_lifetime)) Test58 *ptr = test58_helper();
16671667
char *c = [ptr interior];
16681668
}
1669+
1670+
// rdar://problem/9842343
1671+
void test59(void) {
1672+
extern id test59_getlock(void);
1673+
extern void test59_body(void);
1674+
@synchronized (test59_getlock()) {
1675+
test59_body();
1676+
}
1677+
1678+
// CHECK: define void @test59()
1679+
// CHECK: [[T0:%.*]] = call i8* @test59_getlock()
1680+
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
1681+
// CHECK-NEXT: call void @objc_sync_enter(i8* [[T1]])
1682+
// CHECK-NEXT: call void @test59_body()
1683+
// CHECK-NEXT: call void @objc_sync_exit(i8* [[T1]])
1684+
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
1685+
// CHECK-NEXT: ret void
1686+
}

0 commit comments

Comments
 (0)