diff --git a/clang/include/clang/Parse/Scope.h b/clang/include/clang/Parse/Scope.h index 2efb809bbcca..84bca924f4fa 100644 --- a/clang/include/clang/Parse/Scope.h +++ b/clang/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 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/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 2bb6a17ac108..57ed9884ba74 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/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/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index fe8176f62fc3..1b6d6c14065a 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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 LabelMap; - llvm::SmallVector 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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e99be90963e0..98b8dbc9c071 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2444,6 +2444,8 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) { Decl *decl = static_cast(D); FunctionDecl *FD = cast(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::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(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/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index dc30ac2ea907..cc8678625523 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8604670d6edf..e34a22e039be 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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::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(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/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 990e951c3b62..dfcb65a35323 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -165,12 +165,19 @@ Action::OwningStmtResult Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation ColonLoc, StmtArg subStmt) { Stmt *SubStmt = static_cast(subStmt.release()); - // Look up the record for this label identifier. - LabelStmt *&LabelDecl = LabelMap[II]; + // Look up the record for this label identifier. + 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(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(I->second); return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc)); } diff --git a/clang/test/Sema/block-labels.c b/clang/test/Sema/block-labels.c new file mode 100644 index 000000000000..15e6f61cede3 --- /dev/null +++ b/clang/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'}} +}