diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 11 | ||||
-rw-r--r-- | lib/Parse/RAIIObjectsForParser.h | 149 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 89 |
7 files changed, 189 insertions, 72 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index c7b29d9ba2..2a64be53f7 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 12941b09ba..dbf35b14cf 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index dd8259964c..1baebd5ba9 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/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/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index d906782609..664ba8bc54 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/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/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index ef17aee3f5..f5a6f8fcf9 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/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<const ParsingDeclSpec&>(Declarator::getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(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/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 5853f7f394..ca3e233cb7 100644 --- a/lib/Sema/Sema.cpp +++ b/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/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index c0bc369012..e3a21694ac 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/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); - - // 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; - - if (StackCapacity) - memcpy(newBuffer, oldBuffer, StackCapacity * sizeof(DelayedDiagnostic)); - - delete[] oldBuffer; - Stack = reinterpret_cast<sema::DelayedDiagnostic*>(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]; +void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { + assert(DelayedDiagnostics.getCurrentPool()); + sema::DelayedDiagnosticPool &poppedPool = + *DelayedDiagnostics.getCurrentPool(); + DelayedDiagnostics.popWithoutEmitting(state); + + // 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; + + // 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<DelayedDiagnostic&>(*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) { |