forked from OSchip/llvm-project
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:
parent
02d06b95aa
commit
2ec85375eb
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
delete[] reinterpret_cast<char*>(Stack);
|
||||
}
|
||||
DelayedDiagnostics() : CurPool(0) {}
|
||||
|
||||
/// Adds a delayed diagnostic.
|
||||
void add(const sema::DelayedDiagnostic &diag);
|
||||
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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -16,12 +16,155 @@
|
|||
#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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue