diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 8ed18f521ef1..e1d5b53dec95 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -31,6 +31,9 @@ namespace clang { class DeclGroupRef; class DiagnosticBuilder; class Parser; + class ParsingDeclRAIIObject; + class ParsingDeclSpec; + class ParsingDeclarator; class PragmaUnusedHandler; class ColonProtectionRAIIObject; class InMessageExpressionRAIIObject; @@ -207,6 +210,7 @@ public: const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); } Preprocessor &getPreprocessor() const { return PP; } Sema &getActions() const { return Actions; } + AttributeFactory &getAttrFactory() { return AttrFactory; } const Token &getCurToken() const { return Tok; } Scope *getCurScope() const { return Actions.getCurScope(); } @@ -951,120 +955,7 @@ private: return *ClassStack.top(); } - /// \brief RAII object used to inform the actions that we're - /// currently parsing a declaration. This is active when parsing a - /// variable's initializer, but not when parsing the body of a - /// class or function definition. - class ParsingDeclRAIIObject { - Sema &Actions; - Sema::ParsingDeclState State; - bool Popped; - - public: - ParsingDeclRAIIObject(Parser &P) : Actions(P.Actions) { - push(); - } - - ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *Other) - : Actions(P.Actions) { - if (Other) steal(*Other); - else push(); - } - - /// Creates a RAII object which steals the state from a different - /// object instead of pushing. - ParsingDeclRAIIObject(ParsingDeclRAIIObject &Other) - : Actions(Other.Actions) { - steal(Other); - } - - ~ParsingDeclRAIIObject() { - abort(); - } - - /// Resets the RAII object for a new declaration. - void reset() { - abort(); - push(); - } - - /// Signals that the context was completed without an appropriate - /// declaration being parsed. - void abort() { - pop(0); - } - - void complete(Decl *D) { - assert(!Popped && "ParsingDeclaration has already been popped!"); - pop(D); - } - - private: - void steal(ParsingDeclRAIIObject &Other) { - State = Other.State; - Popped = Other.Popped; - Other.Popped = true; - } - - void push() { - State = Actions.PushParsingDeclaration(); - Popped = false; - } - - void pop(Decl *D) { - if (!Popped) { - Actions.PopParsingDeclaration(State, D); - Popped = true; - } - } - }; - - /// A class for parsing a DeclSpec. - class ParsingDeclSpec : public DeclSpec { - ParsingDeclRAIIObject ParsingRAII; - - public: - ParsingDeclSpec(Parser &P) : DeclSpec(P.AttrFactory), ParsingRAII(P) {} - ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) - : DeclSpec(P.AttrFactory), ParsingRAII(P, RAII) {} - - void complete(Decl *D) { - ParsingRAII.complete(D); - } - - void abort() { - ParsingRAII.abort(); - } - }; - - /// A class for parsing a declarator. - class ParsingDeclarator : public Declarator { - ParsingDeclRAIIObject ParsingRAII; - - public: - ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) - : Declarator(DS, C), ParsingRAII(P) { - } - - const ParsingDeclSpec &getDeclSpec() const { - return static_cast(Declarator::getDeclSpec()); - } - - ParsingDeclSpec &getMutableDeclSpec() const { - return const_cast(getDeclSpec()); - } - - void clear() { - Declarator::clear(); - ParsingRAII.reset(); - } - - void complete(Decl *D) { - ParsingRAII.complete(D); - } - }; - - /// \brief RAII object used to + /// \brief RAII object used to manage the parsing of a class definition. class ParsingClassDefinition { Parser &P; bool Popped; diff --git a/clang/include/clang/Sema/DelayedDiagnostic.h b/clang/include/clang/Sema/DelayedDiagnostic.h index 3320cd815a6b..4f5bc20d4dd9 100644 --- a/clang/include/clang/Sema/DelayedDiagnostic.h +++ b/clang/include/clang/Sema/DelayedDiagnostic.h @@ -21,7 +21,7 @@ #ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H #define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H -#include "clang/AST/DeclCXX.h" +#include "clang/Sema/Sema.h" namespace clang { namespace sema { @@ -214,7 +214,63 @@ private: }; }; +/// DelayedDiagnosticPool - A collection of diagnostics which were +/// delayed. +class DelayedDiagnosticPool { + const DelayedDiagnosticPool *Parent; + llvm::SmallVector Diagnostics; + + // Do not implement. + DelayedDiagnosticPool(const DelayedDiagnosticPool &other); + DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &other); +public: + DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} + ~DelayedDiagnosticPool() { + for (llvm::SmallVectorImpl::iterator + i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) + i->Destroy(); + } + + const DelayedDiagnosticPool *getParent() const { return Parent; } + + /// Does this pool, or any of its ancestors, contain any diagnostics? + bool empty() const { + return (Diagnostics.empty() && (Parent == NULL || Parent->empty())); + } + + /// Add a diagnostic to this pool. + void add(const DelayedDiagnostic &diag) { + Diagnostics.push_back(diag); + } + + /// Steal the diagnostics from the given pool. + void steal(DelayedDiagnosticPool &pool) { + if (pool.Diagnostics.empty()) return; + + if (Diagnostics.empty()) { + Diagnostics = llvm_move(pool.Diagnostics); + } else { + Diagnostics.append(pool.pool_begin(), pool.pool_end()); + } + pool.Diagnostics.clear(); + } + + typedef llvm::SmallVectorImpl::const_iterator + pool_iterator; + pool_iterator pool_begin() const { return Diagnostics.begin(); } + pool_iterator pool_end() const { return Diagnostics.end(); } + bool pool_empty() const { return Diagnostics.empty(); } +}; + } + +/// Add a diagnostic to the current delay pool. +inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { + assert(shouldDelayDiagnostics() && "trying to delay without pool"); + CurPool->add(diag); +} + + } #endif diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c5bd25c7d756..42333ea15d72 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -169,6 +169,7 @@ namespace sema { class BlockScopeInfo; class CompoundScopeInfo; class DelayedDiagnostic; + class DelayedDiagnosticPool; class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; @@ -355,93 +356,63 @@ public: class DelayedDiagnostics; - class ParsingDeclState { - unsigned SavedStackSize; - friend class Sema::DelayedDiagnostics; - }; - - class ProcessingContextState { - unsigned SavedParsingDepth; - unsigned SavedActiveStackBase; + class DelayedDiagnosticsState { + sema::DelayedDiagnosticPool *SavedPool; friend class Sema::DelayedDiagnostics; }; + typedef DelayedDiagnosticsState ParsingDeclState; + typedef DelayedDiagnosticsState ProcessingContextState; /// A class which encapsulates the logic for delaying diagnostics /// during parsing and other processing. class DelayedDiagnostics { - /// \brief The stack of diagnostics that were delayed due to being - /// produced during the parsing of a declaration. - sema::DelayedDiagnostic *Stack; - - /// \brief The number of objects on the delayed-diagnostics stack. - unsigned StackSize; - - /// \brief The current capacity of the delayed-diagnostics stack. - unsigned StackCapacity; - - /// \brief The index of the first "active" delayed diagnostic in - /// the stack. When parsing class definitions, we ignore active - /// delayed diagnostics from the surrounding context. - unsigned ActiveStackBase; - - /// \brief The depth of the declarations we're currently parsing. - /// This gets saved and reset whenever we enter a class definition. - unsigned ParsingDepth; + /// \brief The current pool of diagnostics into which delayed + /// diagnostics should go. + sema::DelayedDiagnosticPool *CurPool; public: - DelayedDiagnostics() : Stack(0), StackSize(0), StackCapacity(0), - ActiveStackBase(0), ParsingDepth(0) {} + DelayedDiagnostics() : CurPool(0) {} - ~DelayedDiagnostics() { - delete[] reinterpret_cast(Stack); - } - - /// Adds a delayed diagnostic. - void add(const sema::DelayedDiagnostic &diag); + /// Adds a delayed diagnostic. + void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h /// Determines whether diagnostics should be delayed. - bool shouldDelayDiagnostics() { return ParsingDepth > 0; } + bool shouldDelayDiagnostics() { return CurPool != 0; } - /// Observe that we've started parsing a declaration. Access and - /// deprecation diagnostics will be delayed; when the declaration - /// is completed, all active delayed diagnostics will be evaluated - /// in its context, and then active diagnostics stack will be - /// popped down to the saved depth. - ParsingDeclState pushParsingDecl() { - ParsingDepth++; + /// Returns the current delayed-diagnostics pool. + sema::DelayedDiagnosticPool *getCurrentPool() const { + return CurPool; + } - ParsingDeclState state; - state.SavedStackSize = StackSize; + /// Enter a new scope. Access and deprecation diagnostics will be + /// collected in this pool. + DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) { + DelayedDiagnosticsState state; + state.SavedPool = CurPool; + CurPool = &pool; return state; } - /// Observe that we're completed parsing a declaration. - static void popParsingDecl(Sema &S, ParsingDeclState state, Decl *decl); - - /// Observe that we've started processing a different context, the - /// contents of which are semantically separate from the - /// declarations it may lexically appear in. This sets aside the - /// current stack of active diagnostics and starts afresh. - ProcessingContextState pushContext() { - assert(StackSize >= ActiveStackBase); - - ProcessingContextState state; - state.SavedParsingDepth = ParsingDepth; - state.SavedActiveStackBase = ActiveStackBase; - - ActiveStackBase = StackSize; - ParsingDepth = 0; + /// Leave a delayed-diagnostic state that was previously pushed. + /// Do not emit any of the diagnostics. This is performed as part + /// of the bookkeeping of popping a pool "properly". + void popWithoutEmitting(DelayedDiagnosticsState state) { + CurPool = state.SavedPool; + } + /// Enter a new scope where access and deprecation diagnostics are + /// not delayed. + DelayedDiagnosticsState pushUndelayed() { + DelayedDiagnosticsState state; + state.SavedPool = CurPool; + CurPool = 0; return state; } - /// Observe that we've stopped processing a context. This - /// restores the previous stack of active diagnostics. - void popContext(ProcessingContextState state) { - assert(ActiveStackBase == StackSize); - assert(ParsingDepth == 0); - ActiveStackBase = state.SavedActiveStackBase; - ParsingDepth = state.SavedParsingDepth; + /// Undo a previous pushUndelayed(). + void popUndelayed(DelayedDiagnosticsState state) { + assert(CurPool == NULL); + CurPool = state.SavedPool; } } DelayedDiagnostics; @@ -456,7 +427,7 @@ public: public: ContextRAII(Sema &S, DeclContext *ContextToPush) : S(S), SavedContext(S.CurContext), - SavedContextState(S.DelayedDiagnostics.pushContext()), + SavedContextState(S.DelayedDiagnostics.pushUndelayed()), SavedCXXThisTypeOverride(S.CXXThisTypeOverride) { assert(ContextToPush && "pushing null context"); @@ -466,7 +437,7 @@ public: void pop() { if (!SavedContext) return; S.CurContext = SavedContext; - S.DelayedDiagnostics.popContext(SavedContextState); + S.DelayedDiagnostics.popUndelayed(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; SavedContext = 0; } @@ -2608,19 +2579,17 @@ public: void DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody); - ParsingDeclState PushParsingDeclaration() { - return DelayedDiagnostics.pushParsingDecl(); - } - void PopParsingDeclaration(ParsingDeclState state, Decl *decl) { - DelayedDiagnostics::popParsingDecl(*this, state, decl); + ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { + return DelayedDiagnostics.push(pool); } + void PopParsingDeclaration(ParsingDeclState state, Decl *decl); typedef ProcessingContextState ParsingClassState; ParsingClassState PushParsingClass() { - return DelayedDiagnostics.pushContext(); + return DelayedDiagnostics.pushUndelayed(); } void PopParsingClass(ParsingClassState state) { - DelayedDiagnostics.popContext(state); + DelayedDiagnostics.popUndelayed(state); } void EmitDeprecationWarning(NamedDecl *D, StringRef Message, diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index c7b29d9ba28e..2a64be53f779 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" #include "clang/AST/DeclTemplate.h" +#include "RAIIObjectsForParser.h" using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 12941b09ba24..dbf35b14cfb8 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2560,7 +2560,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { bool FirstDeclarator = true; SourceLocation CommaLoc; while (1) { - ParsingDeclRAIIObject PD(*this); + ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); FieldDeclarator DeclaratorInfo(DS); DeclaratorInfo.D.setCommaLoc(CommaLoc); @@ -3067,7 +3067,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation EqualLoc; ExprResult AssignedVal; - ParsingDeclRAIIObject PD(*this); + ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index dd8259964c69..1baebd5ba929 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -965,7 +965,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, tok::ObjCKeywordKind MethodImplKind, bool MethodDefinition) { - ParsingDeclRAIIObject PD(*this); + ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index d9067826096b..664ba8bc54b0 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -90,7 +90,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Tell the action that names should be checked in the context of // the declaration to come. - ParsingDeclRAIIObject ParsingTemplateParams(*this); + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // Parse multiple levels of template headers within this template // parameter scope, e.g., @@ -213,10 +214,11 @@ Parser::ParseSingleDeclarationAfterTemplate( return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, prefixAttrs); - // Parse the declaration specifiers, stealing the accumulated - // diagnostics from the template parameters. + // Parse the declaration specifiers, stealing any diagnostics from + // the template parameters. ParsingDeclSpec DS(*this, &DiagsFromTParams); + // Move the attributes from the prefix into the DS. DS.takeAttributesFrom(prefixAttrs); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, @@ -1132,7 +1134,8 @@ Decl *Parser::ParseExplicitInstantiation(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { // This isn't really required here. - ParsingDeclRAIIObject ParsingTemplateParams(*this); + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(ExternLoc, diff --git a/clang/lib/Parse/RAIIObjectsForParser.h b/clang/lib/Parse/RAIIObjectsForParser.h index ef17aee3f512..f5a6f8fcf94a 100644 --- a/clang/lib/Parse/RAIIObjectsForParser.h +++ b/clang/lib/Parse/RAIIObjectsForParser.h @@ -16,13 +16,156 @@ #define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Sema.h" namespace clang { - // TODO: move ParsingDeclRAIIObject here. // TODO: move ParsingClassDefinition here. // TODO: move TentativeParsingAction here. - - + + /// \brief RAII object used to inform the actions that we're + /// currently parsing a declaration. This is active when parsing a + /// variable's initializer, but not when parsing the body of a + /// class or function definition. + class ParsingDeclRAIIObject { + Sema &Actions; + sema::DelayedDiagnosticPool DiagnosticPool; + Sema::ParsingDeclState State; + bool Popped; + + // Do not implement. + ParsingDeclRAIIObject(const ParsingDeclRAIIObject &other); + ParsingDeclRAIIObject &operator=(const ParsingDeclRAIIObject &other); + + public: + enum NoParent_t { NoParent }; + ParsingDeclRAIIObject(Parser &P, NoParent_t _) + : Actions(P.getActions()), DiagnosticPool(NULL) { + push(); + } + + /// Creates a RAII object whose pool is optionally parented by another. + ParsingDeclRAIIObject(Parser &P, + const sema::DelayedDiagnosticPool *parentPool) + : Actions(P.getActions()), DiagnosticPool(parentPool) { + push(); + } + + /// Creates a RAII object and, optionally, initialize its + /// diagnostics pool by stealing the diagnostics from another + /// RAII object (which is assumed to be the current top pool). + ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) + : Actions(P.getActions()), + DiagnosticPool(other ? other->DiagnosticPool.getParent() : NULL) { + if (other) { + DiagnosticPool.steal(other->DiagnosticPool); + other->abort(); + } + push(); + } + + ~ParsingDeclRAIIObject() { + abort(); + } + + sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { + return DiagnosticPool; + } + const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { + return DiagnosticPool; + } + + /// Resets the RAII object for a new declaration. + void reset() { + abort(); + push(); + } + + /// Signals that the context was completed without an appropriate + /// declaration being parsed. + void abort() { + pop(0); + } + + void complete(Decl *D) { + assert(!Popped && "ParsingDeclaration has already been popped!"); + pop(D); + } + + private: + void steal(ParsingDeclRAIIObject &Other) { + DiagnosticPool.steal(Other.DiagnosticPool); + State = Other.State; + Popped = Other.Popped; + Other.Popped = true; + } + + void push() { + State = Actions.PushParsingDeclaration(DiagnosticPool); + Popped = false; + } + + void pop(Decl *D) { + if (!Popped) { + Actions.PopParsingDeclaration(State, D); + Popped = true; + } + } + }; + + /// A class for parsing a DeclSpec. + class ParsingDeclSpec : public DeclSpec { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclSpec(Parser &P) + : DeclSpec(P.getAttrFactory()), + ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} + ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) + : DeclSpec(P.getAttrFactory()), + ParsingRAII(P, RAII) {} + + const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { + return ParsingRAII.getDelayedDiagnosticPool(); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + + void abort() { + ParsingRAII.abort(); + } + }; + + /// A class for parsing a declarator. + class ParsingDeclarator : public Declarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) + : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast(Declarator::getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast(getDeclSpec()); + } + + void clear() { + Declarator::clear(); + ParsingRAII.reset(); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + }; + /// ExtensionRAIIObject - This saves the state of extension warnings when /// constructed and disables them. When destructed, it restores them back to /// the way they used to be. This is used to handle __extension__ in the diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 5853f7f394c8..ca3e233cb7e5 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/APFloat.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/ExternalSemaSource.h" @@ -201,7 +202,6 @@ Sema::~Sema() { ExternalSema->ForgetSema(); } - /// makeUnavailableInSystemHeader - There is an error in the current /// context. If we're still in a system header, and we can plausibly /// make the relevant declaration unavailable instead of erroring, do @@ -426,6 +426,9 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() { /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { + assert(DelayedDiagnostics.getCurrentPool() == NULL + && "reached end of translation unit with a pool attached?"); + // Only complete translation units define vtables and perform implicit // instantiations. if (TUKind == TU_Complete) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index c0bc3690129e..e3a21694ac88 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4198,57 +4198,30 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, diag.Triggered = true; } -// This duplicates a vector push_back but hides the need to know the -// size of the type. -void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) { - assert(StackSize <= StackCapacity); +void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { + assert(DelayedDiagnostics.getCurrentPool()); + sema::DelayedDiagnosticPool &poppedPool = + *DelayedDiagnostics.getCurrentPool(); + DelayedDiagnostics.popWithoutEmitting(state); - // Grow the stack if necessary. - if (StackSize == StackCapacity) { - unsigned newCapacity = 2 * StackCapacity + 2; - char *newBuffer = new char[newCapacity * sizeof(DelayedDiagnostic)]; - const char *oldBuffer = (const char*) Stack; + // When delaying diagnostics to run in the context of a parsed + // declaration, we only want to actually emit anything if parsing + // succeeds. + if (!decl) return; - if (StackCapacity) - memcpy(newBuffer, oldBuffer, StackCapacity * sizeof(DelayedDiagnostic)); - - delete[] oldBuffer; - Stack = reinterpret_cast(newBuffer); - StackCapacity = newCapacity; - } - - assert(StackSize < StackCapacity); - new (&Stack[StackSize++]) DelayedDiagnostic(diag); -} - -void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state, - Decl *decl) { - DelayedDiagnostics &DD = S.DelayedDiagnostics; - - // Check the invariants. - assert(DD.StackSize >= state.SavedStackSize); - assert(state.SavedStackSize >= DD.ActiveStackBase); - assert(DD.ParsingDepth > 0); - - // Drop the parsing depth. - DD.ParsingDepth--; - - // If there are no active diagnostics, we're done. - if (DD.StackSize == DD.ActiveStackBase) - return; - - // We only want to actually emit delayed diagnostics when we - // successfully parsed a decl. - if (decl) { - // We emit all the active diagnostics, not just those starting - // from the saved state. The idea is this: we get one push for a - // decl spec and another for each declarator; in a decl group like: - // deprecated_typedef foo, *bar, baz(); - // only the declarator pops will be passed decls. This is correct; - // we really do need to consider delayed diagnostics from the decl spec - // for each of the different declarations. - for (unsigned i = DD.ActiveStackBase, e = DD.StackSize; i != e; ++i) { - DelayedDiagnostic &diag = DD.Stack[i]; + // We emit all the active diagnostics in this pool or any of its + // parents. In general, we'll get one pool for the decl spec + // and a child pool for each declarator; in a decl group like: + // deprecated_typedef foo, *bar, baz(); + // only the declarator pops will be passed decls. This is correct; + // we really do need to consider delayed diagnostics from the decl spec + // for each of the different declarations. + const sema::DelayedDiagnosticPool *pool = &poppedPool; + do { + for (sema::DelayedDiagnosticPool::pool_iterator + i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) { + // This const_cast is a bit lame. Really, Triggered should be mutable. + DelayedDiagnostic &diag = const_cast(*i); if (diag.Triggered) continue; @@ -4256,25 +4229,19 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state, case DelayedDiagnostic::Deprecation: // Don't bother giving deprecation diagnostics if the decl is invalid. if (!decl->isInvalidDecl()) - S.HandleDelayedDeprecationCheck(diag, decl); + HandleDelayedDeprecationCheck(diag, decl); break; case DelayedDiagnostic::Access: - S.HandleDelayedAccessCheck(diag, decl); + HandleDelayedAccessCheck(diag, decl); break; case DelayedDiagnostic::ForbiddenType: - handleDelayedForbiddenType(S, diag, decl); + handleDelayedForbiddenType(*this, diag, decl); break; } } - } - - // Destroy all the delayed diagnostics we're about to pop off. - for (unsigned i = state.SavedStackSize, e = DD.StackSize; i != e; ++i) - DD.Stack[i].Destroy(); - - DD.StackSize = state.SavedStackSize; + } while ((pool = pool->getParent())); } static bool isDeclDeprecated(Decl *D) {