Skip to content

Commit a95172b

Browse files
committed
Only run the jump-checker if there's a branch-protected scope *and* there's
a switch or goto somewhere in the function. Indirect gotos trigger the jump-checker regardless, because the conditions there are slightly more elaborate and it's too marginal a case to be worth optimizing. Turns off the jump-checker in a lot of cases in C++. rdar://problem/7702918 llvm-svn: 109962
1 parent 82bef97 commit a95172b

File tree

6 files changed

+62
-22
lines changed

6 files changed

+62
-22
lines changed

clang/lib/Sema/Sema.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ using namespace clang;
3131
FunctionScopeInfo::~FunctionScopeInfo() { }
3232

3333
void FunctionScopeInfo::Clear(unsigned NumErrors) {
34-
NeedsScopeChecking = false;
34+
HasBranchProtectedScope = false;
35+
HasBranchIntoScope = false;
36+
HasIndirectGoto = false;
37+
3538
LabelMap.clear();
3639
SwitchStack.clear();
3740
Returns.clear();

clang/lib/Sema/Sema.h

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,15 @@ struct FunctionScopeInfo {
116116
/// a block.
117117
bool IsBlockInfo;
118118

119-
/// \brief Set true when a function, method contains a VLA or ObjC try block,
120-
/// which introduce scopes that need to be checked for goto conditions. If a
121-
/// function does not contain this, then it need not have the jump checker run
122-
/// on it.
123-
bool NeedsScopeChecking;
119+
/// \brief Whether this function contains a VLA, @try, try, C++
120+
/// initializer, or anything else that can't be jumped past.
121+
bool HasBranchProtectedScope;
122+
123+
/// \brief Whether this function contains any switches or direct gotos.
124+
bool HasBranchIntoScope;
125+
126+
/// \brief Whether this function contains any indirect gotos.
127+
bool HasIndirectGoto;
124128

125129
/// \brief The number of errors that had occurred before starting this
126130
/// function or block.
@@ -139,9 +143,17 @@ struct FunctionScopeInfo {
139143
/// block, if there is any chance of applying the named return value
140144
/// optimization.
141145
llvm::SmallVector<ReturnStmt *, 4> Returns;
146+
147+
bool NeedsScopeChecking() const {
148+
return HasIndirectGoto ||
149+
(HasBranchProtectedScope && HasBranchIntoScope);
150+
}
142151

143152
FunctionScopeInfo(unsigned NumErrors)
144-
: IsBlockInfo(false), NeedsScopeChecking(false),
153+
: IsBlockInfo(false),
154+
HasBranchProtectedScope(false),
155+
HasBranchIntoScope(false),
156+
HasIndirectGoto(false),
145157
NumErrorsAtStartOfFunction(NumErrors) { }
146158

147159
virtual ~FunctionScopeInfo();
@@ -706,13 +718,28 @@ class Sema : public Action {
706718

707719
/// \brief Determine whether the current function or block needs scope
708720
/// checking.
709-
bool &FunctionNeedsScopeChecking() {
710-
if (FunctionScopes.empty())
711-
return TopFunctionScope.NeedsScopeChecking;
721+
bool FunctionNeedsScopeChecking() {
722+
if (!FunctionScopes.empty())
723+
return FunctionScopes.back()->NeedsScopeChecking();
724+
return false;
725+
}
712726

713-
return FunctionScopes.back()->NeedsScopeChecking;
727+
void setFunctionHasBranchIntoScope() {
728+
if (!FunctionScopes.empty())
729+
FunctionScopes.back()->HasBranchIntoScope = true;
714730
}
715731

732+
void setFunctionHasBranchProtectedScope() {
733+
if (!FunctionScopes.empty())
734+
FunctionScopes.back()->HasBranchProtectedScope = true;
735+
}
736+
737+
void setFunctionHasIndirectGoto() {
738+
if (!FunctionScopes.empty())
739+
FunctionScopes.back()->HasIndirectGoto = true;
740+
}
741+
742+
716743
bool hasAnyErrorsInThisFunction() const;
717744

718745
/// \brief Retrieve the current block, if any.

clang/lib/Sema/SemaDecl.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2380,7 +2380,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
23802380
// then it shall have block scope.
23812381
QualType T = NewTD->getUnderlyingType();
23822382
if (T->isVariablyModifiedType()) {
2383-
FunctionNeedsScopeChecking() = true;
2383+
setFunctionHasBranchProtectedScope();
23842384

23852385
if (S->getFnParent() == 0) {
23862386
bool SizeIsNegative;
@@ -2794,12 +2794,8 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
27942794
bool isVM = T->isVariablyModifiedType();
27952795
if (isVM || NewVD->hasAttr<CleanupAttr>() ||
27962796
NewVD->hasAttr<BlocksAttr>() ||
2797-
// FIXME: We need to diagnose jumps passed initialized variables in C++.
2798-
// However, this turns on the scope checker for everything with a variable
2799-
// which may impact compile time. See if we can find a better solution
2800-
// to this, perhaps only checking functions that contain gotos in C++?
28012797
(LangOpts.CPlusPlus && NewVD->hasLocalStorage()))
2802-
FunctionNeedsScopeChecking() = true;
2798+
setFunctionHasBranchProtectedScope();
28032799

28042800
if ((isVM && NewVD->hasLinkage()) ||
28052801
(T->isVariableArrayType() && NewVD->hasGlobalStorage())) {

clang/lib/Sema/SemaStmt.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond,
441441
if (!CondExpr)
442442
return StmtError();
443443
}
444+
445+
setFunctionHasBranchIntoScope();
444446

445447
SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, CondExpr);
446448
getSwitchStack().push_back(SS);
@@ -962,6 +964,8 @@ Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
962964
// Look up the record for this label identifier.
963965
LabelStmt *&LabelDecl = getLabelMap()[LabelII];
964966

967+
setFunctionHasBranchIntoScope();
968+
965969
// If we haven't seen this label yet, create a forward reference.
966970
if (LabelDecl == 0)
967971
LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0);
@@ -982,6 +986,9 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
982986
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
983987
return StmtError();
984988
}
989+
990+
setFunctionHasIndirectGoto();
991+
985992
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
986993
}
987994

@@ -1504,7 +1511,7 @@ Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) {
15041511
Action::OwningStmtResult
15051512
Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try,
15061513
MultiStmtArg CatchStmts, StmtArg Finally) {
1507-
FunctionNeedsScopeChecking() = true;
1514+
setFunctionHasBranchProtectedScope();
15081515
unsigned NumCatchStmts = CatchStmts.size();
15091516
return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try.takeAs<Stmt>(),
15101517
(Stmt **)CatchStmts.release(),
@@ -1549,7 +1556,7 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw,
15491556
Action::OwningStmtResult
15501557
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
15511558
StmtArg SynchBody) {
1552-
FunctionNeedsScopeChecking() = true;
1559+
setFunctionHasBranchProtectedScope();
15531560

15541561
// Make sure the expression type is an ObjC pointer or "void *".
15551562
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
@@ -1658,13 +1665,14 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
16581665
}
16591666
}
16601667

1668+
setFunctionHasBranchProtectedScope();
1669+
16611670
// FIXME: We should detect handlers that cannot catch anything because an
16621671
// earlier handler catches a superclass. Need to find a method that is not
16631672
// quadratic for this.
16641673
// Neither of these are explicitly forbidden, but every compiler detects them
16651674
// and warns.
16661675

1667-
FunctionNeedsScopeChecking() = true;
16681676
RawHandlers.release();
16691677
return Owned(CXXTryStmt::Create(Context, TryLoc,
16701678
static_cast<Stmt*>(TryBlock.release()),

clang/test/Analysis/misc-ps.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ void rdar_6777209(char *p) {
298298
typedef void *Opcode;
299299
Opcode pr_4033_getOpcode();
300300
void pr_4033(void) {
301+
void *lbl = &&next_opcode;
301302
next_opcode:
302303
{
303304
Opcode op = pr_4033_getOpcode();

clang/test/CodeGen/statements.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -Wreturn-type < %s -emit-llvm
1+
// RUN: %clang_cc1 -Wreturn-type %s -emit-llvm
22

33
void test1(int x) {
44
switch (x) {
@@ -31,5 +31,10 @@ static long y = &&baz;
3131
}
3232

3333
// PR3869
34-
int test5(long long b) { goto *b; }
34+
int test5(long long b) {
35+
static void *lbls[] = { &&lbl };
36+
goto *b;
37+
lbl:
38+
return 0;
39+
}
3540

0 commit comments

Comments
 (0)