aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Naroff <snaroff@apple.com>2009-02-28 16:48:43 +0000
committerSteve Naroff <snaroff@apple.com>2009-02-28 16:48:43 +0000
commitf3cf89737965352ee02026992e2dc735824e185e (patch)
tree0d89375c08f27cb246c86fa93f7d114a7e4794ca
parent10b26140bcd94373b63ff5c0811a552342c7c512 (diff)
Fix <rdar://problem/6451399> problems with labels and blocks.
- Move the 'LabelMap' from Sema to Scope. To avoid layering problems, the second element is now a 'StmtTy *', which makes the LabelMap a bit more verbose to deal with. - Add 'ActiveScope' to Sema. Managed by ActOnStartOfFunctionDef(), ObjCActOnStartOfMethodDef(), ActOnBlockStmtExpr(). - Changed ActOnLabelStmt(), ActOnGotoStmt(), ActOnAddrLabel(), and ActOnFinishFunctionBody() to use the new ActiveScope. - Added FIXME to workaround in ActOnFinishFunctionBody() (for dealing with C++ nested functions). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65694 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Parse/Scope.h8
-rw-r--r--lib/Sema/Sema.cpp2
-rw-r--r--lib/Sema/Sema.h13
-rw-r--r--lib/Sema/SemaDecl.cpp27
-rw-r--r--lib/Sema/SemaDeclObjC.cpp2
-rw-r--r--lib/Sema/SemaExpr.cpp15
-rw-r--r--lib/Sema/SemaStmt.cpp24
-rw-r--r--test/Sema/block-labels.c17
8 files changed, 89 insertions, 19 deletions
diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h
index 2efb809bbc..84bca924f4 100644
--- a/include/clang/Parse/Scope.h
+++ b/include/clang/Parse/Scope.h
@@ -16,6 +16,7 @@
#include "clang/Parse/Action.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/DenseSet.h"
namespace clang {
@@ -130,6 +131,12 @@ private:
UsingDirectivesTy UsingDirectives;
public:
+ /// LabelMap - This is a mapping from label identifiers to the LabelStmt for
+ /// it (which acts like the label decl in some ways). Forward referenced
+ /// labels have a LabelStmt created for them with a null location & SubStmt.
+ typedef llvm::DenseMap<IdentifierInfo*, Action::StmtTy*> LabelMapTy;
+ LabelMapTy LabelMap;
+
Scope(Scope *Parent, unsigned ScopeFlags) {
Init(Parent, ScopeFlags);
}
@@ -301,6 +308,7 @@ public:
if (Flags & TemplateParamScope) TemplateParamParent = this;
DeclsInScope.clear();
UsingDirectives.clear();
+ LabelMap.clear();
Entity = 0;
}
};
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 2bb6a17ac1..57ed9884ba 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -169,6 +169,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
StdNamespace = 0;
TUScope = 0;
+ ActiveScope = 0;
+
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index fe8176f62f..1b6d6c1406 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -102,15 +102,14 @@ public:
/// the active block object that represents it.
BlockSemaInfo *CurBlock;
+ /// ActiveScope - If inside of a function, method, or block definition,
+ /// this contains a pointer to the active scope that represents it.
+ Scope *ActiveScope;
+
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"
- /// LabelMap - This is a mapping from label identifiers to the LabelStmt for
- /// it (which acts like the label decl in some ways). Forward referenced
- /// labels have a LabelStmt created for them with a null location & SubStmt.
- llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
-
llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
/// ExtVectorDecls - This is a list all the extended vector types. This allows
@@ -2070,6 +2069,10 @@ struct BlockSemaInfo {
/// arguments etc.
Scope *TheScope;
+ /// PrevFunctionScope - This is the scope for the enclosing function.
+ /// For global blocks, this will be null.
+ Scope *PrevFunctionScope;
+
/// ReturnType - This will get set to block result type, by looking at
/// return types, if any, in the block body.
Type *ReturnType;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index e99be90963..98b8dbc9c0 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2444,6 +2444,8 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
Decl *decl = static_cast<Decl*>(D);
FunctionDecl *FD = cast<FunctionDecl>(decl);
+ ActiveScope = FnBodyScope;
+
// See if this is a redefinition.
const FunctionDecl *Definition;
if (FD->getBody(Definition)) {
@@ -2586,17 +2588,29 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
return 0;
}
PopDeclContext();
+
+ // FIXME: Temporary hack to workaround nested C++ functions. For example:
+ // class C2 {
+ // void f() {
+ // class LC1 {
+ // int m() { return 1; }
+ // };
+ // }
+ // };
+ if (ActiveScope == 0)
+ return D;
+
// Verify and clean out per-function state.
- bool HaveLabels = !LabelMap.empty();
+ bool HaveLabels = !ActiveScope->LabelMap.empty();
// Check goto/label use.
- for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
- I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) {
+ for (Scope::LabelMapTy::iterator I = ActiveScope->LabelMap.begin(),
+ E = ActiveScope->LabelMap.end(); I != E; ++I) {
// Verify that we have no forward references left. If so, there was a goto
// or address of a label taken, but no definition of it. Label fwd
// definitions are indicated with a null substmt.
- if (I->second->getSubStmt() == 0) {
- LabelStmt *L = I->second;
+ LabelStmt *L = static_cast<LabelStmt*>(I->second);
+ if (L->getSubStmt() == 0) {
// Emit error.
Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
@@ -2618,7 +2632,8 @@ Sema::DeclTy *Sema::ActOnFinishFunctionBody(DeclTy *D, StmtArg BodyArg) {
}
}
}
- LabelMap.clear();
+ // This reset is for both functions and methods.
+ ActiveScope = 0;
if (!Body) return D;
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index dc30ac2ea9..cc86786255 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -36,6 +36,8 @@ void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) {
// Allow all of Sema to see that we are entering a method definition.
PushDeclContext(FnBodyScope, MDecl);
+ ActiveScope = FnBodyScope;
+
// Create Decl objects for each parameter, entrring them in the scope for
// binding to their use.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 8604670d6e..e34a22e039 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4204,13 +4204,20 @@ Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
SourceLocation LabLoc,
IdentifierInfo *LabelII) {
// Look up the record for this label identifier.
- LabelStmt *&LabelDecl = LabelMap[LabelII];
+ llvm::DenseMap<IdentifierInfo*, Action::StmtTy*>::iterator I =
+ ActiveScope->LabelMap.find(LabelII);
+ LabelStmt *LabelDecl;
+
// If we haven't seen this label yet, create a forward reference. It
// will be validated and/or cleaned up in ActOnFinishFunctionBody.
- if (LabelDecl == 0)
+ if (I == ActiveScope->LabelMap.end()) {
LabelDecl = new (Context) LabelStmt(LabLoc, LabelII, 0);
+ ActiveScope->LabelMap.insert(std::make_pair(LabelII, LabelDecl));
+ } else
+ LabelDecl = static_cast<LabelStmt *>(I->second);
+
// Create the AST node. The address of a label always has type 'void*'.
return new (Context) AddrLabelExpr(OpLoc, LabLoc, LabelDecl,
Context.getPointerType(Context.VoidTy));
@@ -4397,7 +4404,9 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
// Add BSI to CurBlock.
BSI->PrevBlockInfo = CurBlock;
+ BSI->PrevFunctionScope = ActiveScope;
CurBlock = BSI;
+ ActiveScope = BlockScope;
BSI->ReturnType = 0;
BSI->TheScope = BlockScope;
@@ -4492,6 +4501,8 @@ Sema::ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, StmtTy *body,
PopDeclContext();
+ ActiveScope = CurBlock->PrevFunctionScope;
+
// Pop off CurBlock, handle nested blocks.
CurBlock = CurBlock->PrevBlockInfo;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 990e951c3b..dfcb65a353 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -165,12 +165,19 @@ Action::OwningStmtResult
Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II,
SourceLocation ColonLoc, StmtArg subStmt) {
Stmt *SubStmt = static_cast<Stmt*>(subStmt.release());
+
// Look up the record for this label identifier.
- LabelStmt *&LabelDecl = LabelMap[II];
+ Scope::LabelMapTy::iterator I = ActiveScope->LabelMap.find(II);
+ LabelStmt *LabelDecl;
+
// If not forward referenced or defined already, just create a new LabelStmt.
- if (LabelDecl == 0)
- return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt));
+ if (I == ActiveScope->LabelMap.end()) {
+ LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt);
+ ActiveScope->LabelMap.insert(std::make_pair(II, LabelDecl));
+ return Owned(LabelDecl);
+ } else
+ LabelDecl = static_cast<LabelStmt *>(I->second);
assert(LabelDecl->getID() == II && "Label mismatch!");
@@ -672,11 +679,16 @@ Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
return StmtError(Diag(GotoLoc, diag::err_goto_in_block));
// Look up the record for this label identifier.
- LabelStmt *&LabelDecl = LabelMap[LabelII];
+ Scope::LabelMapTy::iterator I = ActiveScope->LabelMap.find(LabelII);
- // If we haven't seen this label yet, create a forward reference.
- if (LabelDecl == 0)
+ LabelStmt *LabelDecl;
+
+ // If not forward referenced or defined already, just create a new LabelStmt.
+ if (I == ActiveScope->LabelMap.end()) {
LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0);
+ ActiveScope->LabelMap.insert(std::make_pair(LabelII, LabelDecl));
+ } else
+ LabelDecl = static_cast<LabelStmt *>(I->second);
return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc));
}
diff --git a/test/Sema/block-labels.c b/test/Sema/block-labels.c
new file mode 100644
index 0000000000..15e6f61ced
--- /dev/null
+++ b/test/Sema/block-labels.c
@@ -0,0 +1,17 @@
+// RUN: clang %s -verify -fblocks -fsyntax-only
+
+int a() {
+ A:if (1) xx();
+ return ^{A:return 1;}();
+}
+int b() {
+ A: return ^{int a; A:return 1;}();
+}
+
+int d() {
+ A: return ^{int a; A: a = ^{int a; A:return 1;}() + ^{int b; A:return 2;}(); return a; }();
+}
+
+int c() {
+ goto A; return ^{ A:return 1;}(); // expected-error {{use of undeclared label 'A'}}
+}