]> granicus.if.org Git - clang/commitdiff
Fix <rdar://problem/6451399> problems with labels and blocks.
authorSteve Naroff <snaroff@apple.com>
Sat, 28 Feb 2009 16:48:43 +0000 (16:48 +0000)
committerSteve Naroff <snaroff@apple.com>
Sat, 28 Feb 2009 16:48:43 +0000 (16:48 +0000)
- 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

include/clang/Parse/Scope.h
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaStmt.cpp
test/Sema/block-labels.c [new file with mode: 0644]

index 2efb809bbcca4be3f0179ba5cdaae85edb52eb22..84bca924f4fa0d0c9a733574caf79a5a168a147a 100644 (file)
@@ -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;
   }
 };
index 2bb6a17ac10861b26ab0fa1527b203c0445e984e..57ed9884ba74f57ebb571a60f42cbf5cddc9bf07 100644 (file)
@@ -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());
       
index fe8176f62fc370d0b442683f0b727858b203d10a..1b6d6c14065af7bab65c44bca5ea522f2fc268b8 100644 (file)
@@ -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;
index e99be90963e02d4d8b5cf82a1b6f4a35335e1684..98b8dbc9c0719e776d60d2754be1c5bfb280959a 100644 (file)
@@ -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;
 
index dc30ac2ea907ffa55bcd1022ecf7b7cedac822c5..cc867862552379e870c7622b886cba993a1b152d 100644 (file)
@@ -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.
 
index 8604670d6edf8333f76ecd145df96082908ce3dc..e34a22e039be663aae117912e509bbdd1f6cb6ef 100644 (file)
@@ -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;
 
index 990e951c3b62d29e3bacb704a95471b551be59cc..dfcb65a35323f97defdcdf94f1e00fea00f9d998 100644 (file)
@@ -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 (file)
index 0000000..15e6f61
--- /dev/null
@@ -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'}}
+}