[cfe-commits] r97518 - in /cfe/trunk: include/clang/Parse/Scope.h lib/Parse/Parser.cpp lib/Sema/Sema.cpp lib/Sema/Sema.h lib/Sema/SemaChecking.cpp lib/Sema/SemaCodeComplete.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclObjC.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaStmt.cpp test/Sema/warn-unused-variables.c test/SemaCXX/local-classes.cpp
Douglas Gregor
dgregor at apple.com
Mon Mar 1 15:15:13 PST 2010
Author: dgregor
Date: Mon Mar 1 17:15:13 2010
New Revision: 97518
URL: http://llvm.org/viewvc/llvm-project?rev=97518&view=rev
Log:
Keep an explicit stack of function and block scopes, each element of
which has the label map, switch statement stack, etc. Previously, we
had a single set of maps in Sema (for the function) along with a stack
of block scopes. However, this lead to funky behavior with nested
functions, e.g., in the member functions of local classes.
The explicit-stack approach is far cleaner, and we retain a 1-element
cache so that we're not malloc/free'ing every time we enter a
function. Fixes PR6382.
Also, tweaked the unused-variable warning suppression logic to look at
errors within a given Scope rather than within a given function. The
prior code wasn't looking at the right number-of-errors count when
dealing with blocks, since the block's count would be deallocated
before we got to ActOnPopScope. This approach works with nested
blocks/functions, and gives tighter error recovery.
Added:
cfe/trunk/test/SemaCXX/local-classes.cpp
Modified:
cfe/trunk/include/clang/Parse/Scope.h
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/lib/Sema/SemaCodeComplete.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/test/Sema/warn-unused-variables.c
Modified: cfe/trunk/include/clang/Parse/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Scope.h?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/trunk/include/clang/Parse/Scope.h Mon Mar 1 17:15:13 2010
@@ -129,6 +129,9 @@
typedef llvm::SmallVector<Action::DeclPtrTy, 2> UsingDirectivesTy;
UsingDirectivesTy UsingDirectives;
+ /// \brief The number of errors at the start of the given scope.
+ unsigned NumErrorsAtStart;
+
public:
Scope(Scope *Parent, unsigned ScopeFlags) {
Init(Parent, ScopeFlags);
@@ -208,6 +211,10 @@
void* getEntity() const { return Entity; }
void setEntity(void *E) { Entity = E; }
+ /// \brief Retrieve the number of errors that had been emitted when we
+ /// entered this scope.
+ unsigned getNumErrorsAtStart() const { return NumErrorsAtStart; }
+
/// isClassScope - Return true if this scope is a class/struct/union scope.
bool isClassScope() const {
return (getFlags() & Scope::ClassScope);
@@ -300,6 +307,7 @@
DeclsInScope.clear();
UsingDirectives.clear();
Entity = 0;
+ NumErrorsAtStart = 0;
}
};
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Mar 1 17:15:13 2010
@@ -274,6 +274,7 @@
} else {
CurScope = new Scope(CurScope, ScopeFlags);
}
+ CurScope->NumErrorsAtStart = Diags.getNumErrors();
}
/// ExitScope - Pop a scope off the scope stack.
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Mon Mar 1 17:15:13 2010
@@ -26,7 +26,18 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
-
+
+FunctionScopeInfo::~FunctionScopeInfo() { }
+
+void FunctionScopeInfo::Clear(unsigned NumErrors) {
+ NeedsScopeChecking = false;
+ LabelMap.clear();
+ SwitchStack.clear();
+ NumErrorsAtStartOfFunction = NumErrors;
+}
+
+BlockScopeInfo::~BlockScopeInfo() { }
+
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
@@ -116,7 +127,7 @@
LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
- CurBlock(0), PackContext(0), ParsingDeclDepth(0),
+ PackContext(0), TopFunctionScope(0), ParsingDeclDepth(0),
IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false),
CompleteTranslationUnit(CompleteTranslationUnit),
@@ -127,8 +138,6 @@
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
- NumErrorsAtStartOfFunction = 0;
-
// Tell diagnostics how to render things from the AST library.
PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
&Context);
@@ -140,6 +149,8 @@
Sema::~Sema() {
if (PackContext) FreePackedContext();
delete TheTargetAttributesSema;
+ while (!FunctionScopes.empty())
+ PopFunctionOrBlockScope();
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
@@ -344,6 +355,51 @@
return Builder;
}
+
+/// \brief Enter a new function scope
+void Sema::PushFunctionScope() {
+ if (FunctionScopes.empty()) {
+ // Use the "top" function scope rather than having to allocate memory for
+ // a new scope.
+ TopFunctionScope.Clear(getDiagnostics().getNumErrors());
+ FunctionScopes.push_back(&TopFunctionScope);
+ return;
+ }
+
+ FunctionScopes.push_back(
+ new FunctionScopeInfo(getDiagnostics().getNumErrors()));
+}
+
+void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
+ FunctionScopes.push_back(new BlockScopeInfo(getDiagnostics().getNumErrors(),
+ BlockScope, Block));
+}
+
+void Sema::PopFunctionOrBlockScope() {
+ if (FunctionScopes.back() != &TopFunctionScope)
+ delete FunctionScopes.back();
+ else
+ TopFunctionScope.Clear(getDiagnostics().getNumErrors());
+
+ FunctionScopes.pop_back();
+}
+
+/// \brief Determine whether any errors occurred within this function/method/
+/// block.
+bool Sema::hasAnyErrorsInThisFunction() const {
+ unsigned NumErrors = TopFunctionScope.NumErrorsAtStartOfFunction;
+ if (!FunctionScopes.empty())
+ NumErrors = FunctionScopes.back()->NumErrorsAtStartOfFunction;
+ return NumErrors != getDiagnostics().getNumErrors();
+}
+
+BlockScopeInfo *Sema::getCurBlock() {
+ if (FunctionScopes.empty())
+ return 0;
+
+ return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+}
+
void Sema::ActOnComment(SourceRange Comment) {
Context.Comments.push_back(Comment);
}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Mar 1 17:15:13 2010
@@ -111,6 +111,19 @@
/// \brief Retains information about a function, method, or block that is
/// currently being parsed.
struct FunctionScopeInfo {
+ /// \brief Whether this scope information structure defined information for
+ /// a block.
+ bool IsBlockInfo;
+
+ /// \brief Set true when a function, method contains a VLA or ObjC try block,
+ /// which introduce scopes that need to be checked for goto conditions. If a
+ /// function does not contain this, then it need not have the jump checker run on it.
+ bool NeedsScopeChecking;
+
+ /// \brief The number of errors that had occurred before starting this
+ /// function or block.
+ unsigned NumErrorsAtStartOfFunction;
+
/// 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.
@@ -120,13 +133,17 @@
/// block.
llvm::SmallVector<SwitchStmt*, 8> SwitchStack;
- /// \brief Whether this scope information structure defined information for
- /// a block.
- bool IsBlockInfo;
-
- FunctionScopeInfo() : IsBlockInfo(false) { }
+ FunctionScopeInfo(unsigned NumErrors)
+ : IsBlockInfo(false), NeedsScopeChecking(false),
+ NumErrorsAtStartOfFunction(NumErrors) { }
+
+ virtual ~FunctionScopeInfo();
+
+ /// \brief Clear out the information in this function scope, making it
+ /// suitable for reuse.
+ void Clear(unsigned NumErrors);
- static bool classof(const FunctionScopeInfo *FSI) { return true; }
+ static bool classof(const FunctionScopeInfo *FSI) { return true; }
};
@@ -147,18 +164,15 @@
/// return types, if any, in the block body.
QualType ReturnType;
- /// SavedNumErrorsAtStartOfFunction - This is the value of the
- /// NumErrorsAtStartOfFunction variable at the point when the block started.
- unsigned SavedNumErrorsAtStartOfFunction;
-
- /// SavedFunctionNeedsScopeChecking - This is the value of
- /// CurFunctionNeedsScopeChecking at the point when the block started.
- bool SavedFunctionNeedsScopeChecking;
+ BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block)
+ : FunctionScopeInfo(NumErrors), hasPrototype(false), isVariadic(false),
+ hasBlockDeclRefExprs(false), TheDecl(Block), TheScope(BlockScope)
+ {
+ IsBlockInfo = true;
+ }
+
+ virtual ~BlockScopeInfo();
- BlockScopeInfo *PrevBlockInfo;
-
- BlockScopeInfo() : FunctionScopeInfo() { IsBlockInfo = true; }
-
static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; }
static bool classof(const BlockScopeInfo *BSI) { return true; }
};
@@ -219,45 +233,25 @@
/// CurContext - This is the current declaration context of parsing.
DeclContext *CurContext;
- /// CurBlock - If inside of a block definition, this contains a pointer to
- /// the active block object that represents it.
- BlockScopeInfo *CurBlock;
-
/// PackContext - Manages the stack for #pragma pack. An alignment
/// of 0 indicates default alignment.
void *PackContext; // Really a "PragmaPackStack*"
- /// FunctionLabelMap - 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.
+ /// \brief Stack containing information about each of the nested function,
+ /// block, and method scopes that are currently active.
+ llvm::SmallVector<FunctionScopeInfo *, 4> FunctionScopes;
+
+ /// \brief Cached function scope object used for the top function scope
+ /// and when there is no function scope (in error cases).
///
- /// Note that this should always be accessed through getLabelMap() in order
- /// to handle blocks properly.
- llvm::DenseMap<IdentifierInfo*, LabelStmt*> FunctionLabelMap;
-
- /// FunctionSwitchStack - This is the current set of active switch statements
- /// in the top level function. Clients should always use getSwitchStack() to
- /// handle the case when they are in a block.
- llvm::SmallVector<SwitchStmt*, 8> FunctionSwitchStack;
-
+ /// This should never be accessed directly; rather, it's address will be
+ /// pushed into \c FunctionScopes when we want to re-use it.
+ FunctionScopeInfo TopFunctionScope;
+
/// ExprTemporaries - This is the stack of temporaries that are created by
/// the current full expression.
llvm::SmallVector<CXXTemporary*, 8> ExprTemporaries;
- /// NumErrorsAtStartOfFunction - This is the number of errors that were
- /// emitted to the diagnostics object at the start of the current
- /// function/method definition. If no additional errors are emitted by the
- /// end of the function, we assume the AST is well formed enough to be
- /// worthwhile to emit control flow diagnostics.
- unsigned NumErrorsAtStartOfFunction;
-
- /// CurFunctionNeedsScopeChecking - This is set to true when a function or
- /// ObjC method body contains a VLA or an ObjC try block, which introduce
- /// scopes that need to be checked for goto conditions. If a function does
- /// not contain this, then it need not have the jump checker run on it.
- bool CurFunctionNeedsScopeChecking;
-
/// ExtVectorDecls - This is a list all the extended vector types. This allows
/// us to associate a raw vector type with one of the ext_vector type names.
/// This is only necessary for issuing pretty diagnostics.
@@ -633,18 +627,42 @@
virtual void ActOnEndOfTranslationUnit();
+ void PushFunctionScope();
+ void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
+ void PopFunctionOrBlockScope();
+
/// getLabelMap() - Return the current label map. If we're in a block, we
/// return it.
llvm::DenseMap<IdentifierInfo*, LabelStmt*> &getLabelMap() {
- return CurBlock ? CurBlock->LabelMap : FunctionLabelMap;
+ if (FunctionScopes.empty())
+ return TopFunctionScope.LabelMap;
+
+ return FunctionScopes.back()->LabelMap;
}
/// getSwitchStack - This is returns the switch stack for the current block or
/// function.
llvm::SmallVector<SwitchStmt*,8> &getSwitchStack() {
- return CurBlock ? CurBlock->SwitchStack : FunctionSwitchStack;
+ if (FunctionScopes.empty())
+ return TopFunctionScope.SwitchStack;
+
+ return FunctionScopes.back()->SwitchStack;
}
+ /// \brief Determine whether the current function or block needs scope
+ /// checking.
+ bool &FunctionNeedsScopeChecking() {
+ if (FunctionScopes.empty())
+ return TopFunctionScope.NeedsScopeChecking;
+
+ return FunctionScopes.back()->NeedsScopeChecking;
+ }
+
+ bool hasAnyErrorsInThisFunction() const;
+
+ /// \brief Retrieve the current block, if any.
+ BlockScopeInfo *getCurBlock();
+
/// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls
llvm::SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Mon Mar 1 17:15:13 2010
@@ -506,6 +506,7 @@
}
// Determine whether the current function is variadic or not.
+ BlockScopeInfo *CurBlock = getCurBlock();
bool isVariadic;
if (CurBlock)
isVariadic = CurBlock->isVariadic;
Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Mon Mar 1 17:15:13 2010
@@ -1137,8 +1137,9 @@
else if (ObjCMethodDecl *Method
= dyn_cast<ObjCMethodDecl>(SemaRef.CurContext))
isVoid = Method->getResultType()->isVoidType();
- else if (SemaRef.CurBlock && !SemaRef.CurBlock->ReturnType.isNull())
- isVoid = SemaRef.CurBlock->ReturnType->isVoidType();
+ else if (SemaRef.getCurBlock() &&
+ !SemaRef.getCurBlock()->ReturnType.isNull())
+ isVoid = SemaRef.getCurBlock()->ReturnType->isVoidType();
Pattern = new CodeCompletionString;
Pattern->AddTypedTextChunk("return");
if (!isVoid) {
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Mar 1 17:15:13 2010
@@ -553,8 +553,8 @@
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (ShouldDiagnoseUnusedDecl(D) &&
- NumErrorsAtStartOfFunction == getDiagnostics().getNumErrors())
+ if (ShouldDiagnoseUnusedDecl(D) &&
+ S->getNumErrorsAtStart() == getDiagnostics().getNumErrors())
Diag(D->getLocation(), diag::warn_unused_variable) << D->getDeclName();
// Remove this name from our lexical scope.
@@ -2180,7 +2180,7 @@
// then it shall have block scope.
QualType T = NewTD->getUnderlyingType();
if (T->isVariablyModifiedType()) {
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
if (S->getFnParent() == 0) {
bool SizeIsNegative;
@@ -2507,7 +2507,7 @@
// which may impact compile time. See if we can find a better solution
// to this, perhaps only checking functions that contain gotos in C++?
(LangOpts.CPlusPlus && NewVD->hasLocalStorage()))
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
if ((isVM && NewVD->hasLinkage()) ||
(T->isVariableArrayType() && NewVD->hasGlobalStorage())) {
@@ -4084,8 +4084,8 @@
else
FD = cast<FunctionDecl>(D.getAs<Decl>());
- CurFunctionNeedsScopeChecking = false;
- NumErrorsAtStartOfFunction = getDiagnostics().getNumErrors();
+ // Enter a new function scope
+ PushFunctionScope();
// See if this is a redefinition.
// But don't complain if we're in GNU89 mode and the previous definition
@@ -4217,11 +4217,9 @@
// Verify and clean out per-function state.
- assert(&getLabelMap() == &FunctionLabelMap && "Didn't pop block right?");
-
// Check goto/label use.
for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
- I = FunctionLabelMap.begin(), E = FunctionLabelMap.end(); I != E; ++I) {
+ I = getLabelMap().begin(), E = getLabelMap().end(); I != E; ++I) {
LabelStmt *L = I->second;
// Verify that we have no forward references left. If so, there was a goto
@@ -4257,25 +4255,34 @@
Elements.push_back(L);
Compound->setStmts(Context, &Elements[0], Elements.size());
}
- FunctionLabelMap.clear();
-
- if (!Body) return D;
- CheckUnreachable(AC);
+ if (Body) {
+ CheckUnreachable(AC);
+ // C++ constructors that have function-try-blocks can't have return
+ // statements in the handlers of that block. (C++ [except.handle]p14)
+ // Verify this.
+ if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
+ DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
+
+ // Verify that that gotos and switch cases don't jump into scopes illegally.
// Verify that that gotos and switch cases don't jump into scopes illegally.
- if (CurFunctionNeedsScopeChecking &&
- NumErrorsAtStartOfFunction == getDiagnostics().getNumErrors())
- DiagnoseInvalidJumps(Body);
-
- // C++ constructors that have function-try-blocks can't have return
- // statements in the handlers of that block. (C++ [except.handle]p14)
- // Verify this.
- if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
- DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
+ if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
+ DiagnoseInvalidJumps(Body);
- if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
- MarkBaseAndMemberDestructorsReferenced(Destructor);
+ if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl))
+ MarkBaseAndMemberDestructorsReferenced(Destructor);
+
+ // If any errors have occurred, clear out any temporaries that may have
+ // been leftover. This ensures that these temporaries won't be picked up for
+ // deletion in some later function.
+ if (PP.getDiagnostics().hasErrorOccurred())
+ ExprTemporaries.clear();
+
+ assert(ExprTemporaries.empty() && "Leftover temporaries in function");
+ }
+
+ PopFunctionOrBlockScope();
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
@@ -4283,7 +4290,6 @@
if (getDiagnostics().hasErrorOccurred())
ExprTemporaries.clear();
- assert(ExprTemporaries.empty() && "Leftover temporaries in function");
return D;
}
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Mar 1 17:15:13 2010
@@ -49,9 +49,6 @@
if (!MDecl)
return;
- CurFunctionNeedsScopeChecking = false;
- NumErrorsAtStartOfFunction = getDiagnostics().getNumErrors();
-
// Allow the rest of sema to find private method decl implementations.
if (MDecl->isInstanceMethod())
AddInstanceMethodToGlobalPool(MDecl);
@@ -60,7 +57,8 @@
// Allow all of Sema to see that we are entering a method definition.
PushDeclContext(FnBodyScope, MDecl);
-
+ PushFunctionScope();
+
// Create Decl objects for each parameter, entrring them in the scope for
// binding to their use.
@@ -1989,7 +1987,7 @@
// Make sure we can establish a context for the method.
if (!ClassDecl) {
Diag(MethodLoc, diag::error_missing_method_context);
- FunctionLabelMap.clear();
+ getLabelMap().clear();
return DeclPtrTy();
}
QualType resultDeclType;
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Mar 1 17:15:13 2010
@@ -396,7 +396,7 @@
/// This also keeps the 'hasBlockDeclRefExprs' in the BlockScopeInfo records
/// up-to-date.
///
-static bool ShouldSnapshotBlockValueReference(BlockScopeInfo *CurBlock,
+static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock,
ValueDecl *VD) {
// If the value is defined inside the block, we couldn't snapshot it even if
// we wanted to.
@@ -421,8 +421,12 @@
// which case that outer block doesn't get "hasBlockDeclRefExprs") or it may
// be defined outside all of the current blocks (in which case the blocks do
// all get the bit). Walk the nesting chain.
- for (BlockScopeInfo *NextBlock = CurBlock->PrevBlockInfo; NextBlock;
- NextBlock = NextBlock->PrevBlockInfo) {
+ for (unsigned I = S.FunctionScopes.size() - 1; I; --I) {
+ BlockScopeInfo *NextBlock = dyn_cast<BlockScopeInfo>(S.FunctionScopes[I]);
+
+ if (!NextBlock)
+ continue;
+
// If we found the defining block for the variable, don't mark the block as
// having a reference outside it.
if (NextBlock->TheDecl == VD->getDeclContext())
@@ -1597,7 +1601,8 @@
// We do not do this for things like enum constants, global variables, etc,
// as they do not get snapshotted.
//
- if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
+ if (getCurBlock() &&
+ ShouldSnapshotBlockValueReference(*this, getCurBlock(), VD)) {
if (VD->getType().getTypePtr()->isVariablyModifiedType()) {
Diag(Loc, diag::err_ref_vm_type);
Diag(D->getLocation(), diag::note_declared_at);
@@ -6722,30 +6727,16 @@
/// ActOnBlockStart - This callback is invoked when a block literal is started.
void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
- // Analyze block parameters.
- BlockScopeInfo *BSI = new BlockScopeInfo();
-
- // Add BSI to CurBlock.
- BSI->PrevBlockInfo = CurBlock;
- CurBlock = BSI;
-
- BSI->ReturnType = QualType();
- BSI->TheScope = BlockScope;
- BSI->hasBlockDeclRefExprs = false;
- BSI->hasPrototype = false;
- BSI->SavedFunctionNeedsScopeChecking = CurFunctionNeedsScopeChecking;
- BSI->SavedNumErrorsAtStartOfFunction = NumErrorsAtStartOfFunction;
- CurFunctionNeedsScopeChecking = false;
- NumErrorsAtStartOfFunction = getDiagnostics().getNumErrors();
-
- BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc);
- CurContext->addDecl(BSI->TheDecl);
- PushDeclContext(BlockScope, BSI->TheDecl);
+ BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
+ PushBlockScope(BlockScope, Block);
+ CurContext->addDecl(Block);
+ PushDeclContext(BlockScope, Block);
}
void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
-
+ BlockScopeInfo *CurBlock = getCurBlock();
+
if (ParamInfo.getNumTypeObjects() == 0
|| ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
@@ -6847,15 +6838,9 @@
/// ActOnBlockError - If there is an error parsing a block, this callback
/// is invoked to pop the information about the block from the action impl.
void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) {
- // Ensure that CurBlock is deleted.
- llvm::OwningPtr<BlockScopeInfo> CC(CurBlock);
-
- CurFunctionNeedsScopeChecking = CurBlock->SavedFunctionNeedsScopeChecking;
- NumErrorsAtStartOfFunction = CurBlock->SavedNumErrorsAtStartOfFunction;
-
// Pop off CurBlock, handle nested blocks.
PopDeclContext();
- CurBlock = CurBlock->PrevBlockInfo;
+ PopFunctionOrBlockScope();
// FIXME: Delete the ParmVarDecl objects as well???
}
@@ -6867,14 +6852,10 @@
if (!LangOpts.Blocks)
Diag(CaretLoc, diag::err_blocks_disable);
- // Ensure that CurBlock is deleted.
- llvm::OwningPtr<BlockScopeInfo> BSI(CurBlock);
+ BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back());
PopDeclContext();
- // Pop off CurBlock, handle nested blocks.
- CurBlock = CurBlock->PrevBlockInfo;
-
QualType RetTy = Context.VoidTy;
if (!BSI->ReturnType.isNull())
RetTy = BSI->ReturnType;
@@ -6898,12 +6879,8 @@
BlockTy = Context.getBlockPointerType(BlockTy);
// If needed, diagnose invalid gotos and switches in the block.
- if (CurFunctionNeedsScopeChecking &&
- NumErrorsAtStartOfFunction == getDiagnostics().getNumErrors())
+ if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction())
DiagnoseInvalidJumps(static_cast<CompoundStmt*>(body.get()));
-
- CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
- NumErrorsAtStartOfFunction = BSI->SavedNumErrorsAtStartOfFunction;
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
@@ -6922,15 +6899,18 @@
Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
Good = false;
}
- BSI->LabelMap.clear();
- if (!Good)
+ if (!Good) {
+ PopFunctionOrBlockScope();
return ExprError();
-
+ }
+
AnalysisContext AC(BSI->TheDecl);
CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
CheckUnreachable(AC);
- return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
- BSI->hasBlockDeclRefExprs));
+ Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy,
+ BSI->hasBlockDeclRefExprs);
+ PopFunctionOrBlockScope();
+ return Owned(Result);
}
Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Mon Mar 1 17:15:13 2010
@@ -1036,6 +1036,7 @@
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// If this is the first return we've seen in the block, infer the type of
// the block from it.
+ BlockScopeInfo *CurBlock = getCurBlock();
if (CurBlock->ReturnType.isNull()) {
if (RetValExp) {
// Don't call UsualUnaryConversions(), since we don't want to do
@@ -1130,7 +1131,7 @@
Action::OwningStmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
Expr *RetValExp = rex.takeAs<Expr>();
- if (CurBlock)
+ if (getCurBlock())
return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
QualType FnRetType;
@@ -1500,7 +1501,7 @@
Action::OwningStmtResult
Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
StmtArg Try, StmtArg Catch, StmtArg Finally) {
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
return Owned(new (Context) ObjCAtTryStmt(AtLoc, Try.takeAs<Stmt>(),
Catch.takeAs<Stmt>(),
Finally.takeAs<Stmt>()));
@@ -1533,7 +1534,7 @@
Action::OwningStmtResult
Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr,
StmtArg SynchBody) {
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
// Make sure the expression type is an ObjC pointer or "void *".
Expr *SyncExpr = static_cast<Expr*>(SynchExpr.get());
@@ -1643,7 +1644,7 @@
// Neither of these are explicitly forbidden, but every compiler detects them
// and warns.
- CurFunctionNeedsScopeChecking = true;
+ FunctionNeedsScopeChecking() = true;
RawHandlers.release();
return Owned(CXXTryStmt::Create(Context, TryLoc,
static_cast<Stmt*>(TryBlock.release()),
Modified: cfe/trunk/test/Sema/warn-unused-variables.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/warn-unused-variables.c?rev=97518&r1=97517&r2=97518&view=diff
==============================================================================
--- cfe/trunk/test/Sema/warn-unused-variables.c (original)
+++ cfe/trunk/test/Sema/warn-unused-variables.c Mon Mar 1 17:15:13 2010
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -fblocks -verify %s
struct s0 {
unsigned int i;
@@ -23,3 +23,10 @@
int X = 4; // Shouldn't have a bogus 'unused variable X' warning.
return Y + X; // expected-error {{use of undeclared identifier 'Y'}}
}
+
+int f3() {
+ int X1 = 4;
+ (void)(Y1 + X1); // expected-error {{use of undeclared identifier 'Y1'}}
+ (void)(^() { int X = 4; }); // expected-warning{{unused}}
+ (void)(^() { int X = 4; return Y + X; }); // expected-error {{use of undeclared identifier 'Y'}}
+}
Added: cfe/trunk/test/SemaCXX/local-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/local-classes.cpp?rev=97518&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/local-classes.cpp (added)
+++ cfe/trunk/test/SemaCXX/local-classes.cpp Mon Mar 1 17:15:13 2010
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR6382 {
+ int foo()
+ {
+ goto error;
+ {
+ struct BitPacker {
+ BitPacker() {}
+ };
+ BitPacker packer;
+ }
+
+ error:
+ return -1;
+ }
+}
More information about the cfe-commits
mailing list