Refactor DelayedDiagnostics so that it keeps diagnostics in

separate pools owned by the RAII objects that keep pushing
decl state.  This gives us quite a bit more flexibility.

llvm-svn: 156289
This commit is contained in:
John McCall 2012-05-07 06:16:41 +00:00
parent 02d06b95aa
commit 2ec85375eb
10 changed files with 294 additions and 261 deletions

View File

@ -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<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);
}
};
/// \brief RAII object used to
/// \brief RAII object used to manage the parsing of a class definition.
class ParsingClassDefinition {
Parser &P;
bool Popped;

View File

@ -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<DelayedDiagnostic, 4> Diagnostics;
// Do not implement.
DelayedDiagnosticPool(const DelayedDiagnosticPool &other);
DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &other);
public:
DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {}
~DelayedDiagnosticPool() {
for (llvm::SmallVectorImpl<DelayedDiagnostic>::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<DelayedDiagnostic>::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

View File

@ -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<char*>(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,

View File

@ -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

View File

@ -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();

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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) {

View File

@ -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<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];
// 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) {