diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-03-01 23:15:13 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-03-01 23:15:13 +0000 |
commit | 9ea9bdbc14374f7bacdb50d3e52c664ff12150ff (patch) | |
tree | 26b4cdeaef74f71025025825a4f13b5fef0d9b44 /lib/Sema/Sema.cpp | |
parent | 7bf3600f56342dc434dad994d0c71068e5d3b5c7 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97518 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r-- | lib/Sema/Sema.cpp | 64 |
1 files changed, 60 insertions, 4 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index fb7d1991fb..3b4afef70b 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, 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 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, 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(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, 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 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { 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); } |