aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def3
-rw-r--r--lib/Sema/Sema.h13
-rw-r--r--lib/Sema/SemaDecl.cpp89
-rw-r--r--test/Sema/scope-check.c8
4 files changed, 111 insertions, 2 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index e1c0af4659..99b61cc8ff 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -744,6 +744,9 @@ DIAG(err_redefinition_of_label, ERROR,
DIAG(err_undeclared_label_use, ERROR,
"use of undeclared label '%0'")
+DIAG(err_goto_into_scope, ERROR,
+ "illegal jump (scoping violation)")
+
DIAG(ext_implicit_function_decl, EXTENSION,
"implicit declaration of function %0 is invalid in C99")
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 45ea16df53..fe8176f62f 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -383,6 +383,19 @@ public:
return IdResolver.isDeclInScope(D, Ctx, Context, S);
}
+
+ void RecursiveCalcJumpScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+ llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+ llvm::DenseMap<Stmt*, void*>& GotoScopeMap,
+ std::vector<void*>& ScopeStack,
+ Stmt* CurStmt);
+
+ void RecursiveCalcLabelScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+ llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+ std::vector<void*>& ScopeStack,
+ Stmt* CurStmt,
+ Stmt* ParentCompoundStmt);
+
/// Subroutines of ActOnDeclarator().
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
Decl *LastDecl);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 6dbb66a4b7..8a4ffaf65d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2496,6 +2496,79 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
return FD;
}
+static bool StatementCreatesScope(Stmt* S) {
+ bool result = false;
+ if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+ for (DeclStmt::decl_iterator i = DS->decl_begin();
+ i != DS->decl_end(); ++i) {
+ if (VarDecl* D = dyn_cast<VarDecl>(*i)) {
+ result |= D->getType()->isVariablyModifiedType();
+ }
+ }
+ }
+
+ return result;
+}
+
+void Sema::RecursiveCalcLabelScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+ llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+ std::vector<void*>& ScopeStack,
+ Stmt* CurStmt,
+ Stmt* ParentCompoundStmt) {
+ for (Stmt::child_iterator i = CurStmt->child_begin();
+ i != CurStmt->child_end(); ++i) {
+ if (!*i) continue;
+ if (StatementCreatesScope(*i)) {
+ ScopeStack.push_back(*i);
+ PopScopeMap[*i] = ParentCompoundStmt;
+ } else if (isa<LabelStmt>(CurStmt)) {
+ LabelScopeMap[CurStmt] = ScopeStack.size() ? ScopeStack.back() : 0;
+ }
+ if (isa<DeclStmt>(*i)) continue;
+ Stmt* CurCompound = isa<CompoundStmt>(*i) ? *i : ParentCompoundStmt;
+ RecursiveCalcLabelScopes(LabelScopeMap, PopScopeMap, ScopeStack,
+ *i, CurCompound);
+ }
+
+ while (ScopeStack.size() && PopScopeMap[ScopeStack.back()] == CurStmt) {
+ ScopeStack.pop_back();
+ }
+}
+
+void Sema::RecursiveCalcJumpScopes(llvm::DenseMap<Stmt*, void*>& LabelScopeMap,
+ llvm::DenseMap<void*, Stmt*>& PopScopeMap,
+ llvm::DenseMap<Stmt*, void*>& GotoScopeMap,
+ std::vector<void*>& ScopeStack,
+ Stmt* CurStmt) {
+ for (Stmt::child_iterator i = CurStmt->child_begin();
+ i != CurStmt->child_end(); ++i) {
+ if (!*i) continue;
+ if (StatementCreatesScope(*i)) {
+ ScopeStack.push_back(*i);
+ } else if (GotoStmt* GS = dyn_cast<GotoStmt>(*i)) {
+ void* LScope = LabelScopeMap[GS->getLabel()];
+ if (LScope) {
+ bool foundScopeInStack = false;
+ for (unsigned i = ScopeStack.size(); i > 0; --i) {
+ if (LScope == ScopeStack[i-1]) {
+ foundScopeInStack = true;
+ break;
+ }
+ }
+ if (!foundScopeInStack) {
+ Diag(GS->getSourceRange().getBegin(), diag::err_goto_into_scope);
+ }
+ }
+ }
+ if (isa<DeclStmt>(*i)) continue;
+ RecursiveCalcJumpScopes(LabelScopeMap, PopScopeMap, GotoScopeMap, ScopeStack, *i);
+ }
+
+ while (ScopeStack.size() && PopScopeMap[ScopeStack.back()] == CurStmt) {
+ ScopeStack.pop_back();
+ }
+}
+
Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
Decl *dcl = static_cast<Decl *>(D);
Stmt *Body = static_cast<Stmt*>(BodyArg.release());
@@ -2511,7 +2584,8 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
}
PopDeclContext();
// Verify and clean out per-function state.
-
+
+ bool HaveLabels = !LabelMap.empty();
// Check goto/label use.
for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) {
@@ -2542,7 +2616,18 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
}
}
LabelMap.clear();
-
+
+ if (!Body) return D;
+
+ if (HaveLabels) {
+ llvm::DenseMap<Stmt*, void*> LabelScopeMap;
+ llvm::DenseMap<void*, Stmt*> PopScopeMap;
+ llvm::DenseMap<Stmt*, void*> GotoScopeMap;
+ std::vector<void*> ScopeStack;
+ RecursiveCalcLabelScopes(LabelScopeMap, PopScopeMap, ScopeStack, Body, Body);
+ RecursiveCalcJumpScopes(LabelScopeMap, PopScopeMap, GotoScopeMap, ScopeStack, Body);
+ }
+
return D;
}
diff --git a/test/Sema/scope-check.c b/test/Sema/scope-check.c
new file mode 100644
index 0000000000..0eb134cbd3
--- /dev/null
+++ b/test/Sema/scope-check.c
@@ -0,0 +1,8 @@
+// RUN: clang -fsyntax-only -verify %s
+
+int test1(int x) {
+ goto L; // expected-error{{illegal jump}}
+ int a[x];
+ L:
+ return sizeof a;
+}