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 DeclGroupRef;
|
||||||
class DiagnosticBuilder;
|
class DiagnosticBuilder;
|
||||||
class Parser;
|
class Parser;
|
||||||
|
class ParsingDeclRAIIObject;
|
||||||
|
class ParsingDeclSpec;
|
||||||
|
class ParsingDeclarator;
|
||||||
class PragmaUnusedHandler;
|
class PragmaUnusedHandler;
|
||||||
class ColonProtectionRAIIObject;
|
class ColonProtectionRAIIObject;
|
||||||
class InMessageExpressionRAIIObject;
|
class InMessageExpressionRAIIObject;
|
||||||
|
@ -207,6 +210,7 @@ public:
|
||||||
const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); }
|
const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); }
|
||||||
Preprocessor &getPreprocessor() const { return PP; }
|
Preprocessor &getPreprocessor() const { return PP; }
|
||||||
Sema &getActions() const { return Actions; }
|
Sema &getActions() const { return Actions; }
|
||||||
|
AttributeFactory &getAttrFactory() { return AttrFactory; }
|
||||||
|
|
||||||
const Token &getCurToken() const { return Tok; }
|
const Token &getCurToken() const { return Tok; }
|
||||||
Scope *getCurScope() const { return Actions.getCurScope(); }
|
Scope *getCurScope() const { return Actions.getCurScope(); }
|
||||||
|
@ -951,120 +955,7 @@ private:
|
||||||
return *ClassStack.top();
|
return *ClassStack.top();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief RAII object used to inform the actions that we're
|
/// \brief RAII object used to manage the parsing of a class definition.
|
||||||
/// 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
|
|
||||||
class ParsingClassDefinition {
|
class ParsingClassDefinition {
|
||||||
Parser &P;
|
Parser &P;
|
||||||
bool Popped;
|
bool Popped;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
|
#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H
|
||||||
#define 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 clang {
|
||||||
namespace sema {
|
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
|
#endif
|
||||||
|
|
|
@ -169,6 +169,7 @@ namespace sema {
|
||||||
class BlockScopeInfo;
|
class BlockScopeInfo;
|
||||||
class CompoundScopeInfo;
|
class CompoundScopeInfo;
|
||||||
class DelayedDiagnostic;
|
class DelayedDiagnostic;
|
||||||
|
class DelayedDiagnosticPool;
|
||||||
class FunctionScopeInfo;
|
class FunctionScopeInfo;
|
||||||
class LambdaScopeInfo;
|
class LambdaScopeInfo;
|
||||||
class PossiblyUnreachableDiag;
|
class PossiblyUnreachableDiag;
|
||||||
|
@ -355,93 +356,63 @@ public:
|
||||||
|
|
||||||
class DelayedDiagnostics;
|
class DelayedDiagnostics;
|
||||||
|
|
||||||
class ParsingDeclState {
|
class DelayedDiagnosticsState {
|
||||||
unsigned SavedStackSize;
|
sema::DelayedDiagnosticPool *SavedPool;
|
||||||
friend class Sema::DelayedDiagnostics;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ProcessingContextState {
|
|
||||||
unsigned SavedParsingDepth;
|
|
||||||
unsigned SavedActiveStackBase;
|
|
||||||
friend class Sema::DelayedDiagnostics;
|
friend class Sema::DelayedDiagnostics;
|
||||||
};
|
};
|
||||||
|
typedef DelayedDiagnosticsState ParsingDeclState;
|
||||||
|
typedef DelayedDiagnosticsState ProcessingContextState;
|
||||||
|
|
||||||
/// A class which encapsulates the logic for delaying diagnostics
|
/// A class which encapsulates the logic for delaying diagnostics
|
||||||
/// during parsing and other processing.
|
/// during parsing and other processing.
|
||||||
class DelayedDiagnostics {
|
class DelayedDiagnostics {
|
||||||
/// \brief The stack of diagnostics that were delayed due to being
|
/// \brief The current pool of diagnostics into which delayed
|
||||||
/// produced during the parsing of a declaration.
|
/// diagnostics should go.
|
||||||
sema::DelayedDiagnostic *Stack;
|
sema::DelayedDiagnosticPool *CurPool;
|
||||||
|
|
||||||
/// \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;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DelayedDiagnostics() : Stack(0), StackSize(0), StackCapacity(0),
|
DelayedDiagnostics() : CurPool(0) {}
|
||||||
ActiveStackBase(0), ParsingDepth(0) {}
|
|
||||||
|
|
||||||
~DelayedDiagnostics() {
|
/// Adds a delayed diagnostic.
|
||||||
delete[] reinterpret_cast<char*>(Stack);
|
void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a delayed diagnostic.
|
|
||||||
void add(const sema::DelayedDiagnostic &diag);
|
|
||||||
|
|
||||||
/// Determines whether diagnostics should be delayed.
|
/// 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
|
/// Returns the current delayed-diagnostics pool.
|
||||||
/// deprecation diagnostics will be delayed; when the declaration
|
sema::DelayedDiagnosticPool *getCurrentPool() const {
|
||||||
/// is completed, all active delayed diagnostics will be evaluated
|
return CurPool;
|
||||||
/// in its context, and then active diagnostics stack will be
|
}
|
||||||
/// popped down to the saved depth.
|
|
||||||
ParsingDeclState pushParsingDecl() {
|
|
||||||
ParsingDepth++;
|
|
||||||
|
|
||||||
ParsingDeclState state;
|
/// Enter a new scope. Access and deprecation diagnostics will be
|
||||||
state.SavedStackSize = StackSize;
|
/// collected in this pool.
|
||||||
|
DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) {
|
||||||
|
DelayedDiagnosticsState state;
|
||||||
|
state.SavedPool = CurPool;
|
||||||
|
CurPool = &pool;
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Observe that we're completed parsing a declaration.
|
/// Leave a delayed-diagnostic state that was previously pushed.
|
||||||
static void popParsingDecl(Sema &S, ParsingDeclState state, Decl *decl);
|
/// Do not emit any of the diagnostics. This is performed as part
|
||||||
|
/// of the bookkeeping of popping a pool "properly".
|
||||||
/// Observe that we've started processing a different context, the
|
void popWithoutEmitting(DelayedDiagnosticsState state) {
|
||||||
/// contents of which are semantically separate from the
|
CurPool = state.SavedPool;
|
||||||
/// 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;
|
|
||||||
|
|
||||||
|
/// Enter a new scope where access and deprecation diagnostics are
|
||||||
|
/// not delayed.
|
||||||
|
DelayedDiagnosticsState pushUndelayed() {
|
||||||
|
DelayedDiagnosticsState state;
|
||||||
|
state.SavedPool = CurPool;
|
||||||
|
CurPool = 0;
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Observe that we've stopped processing a context. This
|
/// Undo a previous pushUndelayed().
|
||||||
/// restores the previous stack of active diagnostics.
|
void popUndelayed(DelayedDiagnosticsState state) {
|
||||||
void popContext(ProcessingContextState state) {
|
assert(CurPool == NULL);
|
||||||
assert(ActiveStackBase == StackSize);
|
CurPool = state.SavedPool;
|
||||||
assert(ParsingDepth == 0);
|
|
||||||
ActiveStackBase = state.SavedActiveStackBase;
|
|
||||||
ParsingDepth = state.SavedParsingDepth;
|
|
||||||
}
|
}
|
||||||
} DelayedDiagnostics;
|
} DelayedDiagnostics;
|
||||||
|
|
||||||
|
@ -456,7 +427,7 @@ public:
|
||||||
public:
|
public:
|
||||||
ContextRAII(Sema &S, DeclContext *ContextToPush)
|
ContextRAII(Sema &S, DeclContext *ContextToPush)
|
||||||
: S(S), SavedContext(S.CurContext),
|
: S(S), SavedContext(S.CurContext),
|
||||||
SavedContextState(S.DelayedDiagnostics.pushContext()),
|
SavedContextState(S.DelayedDiagnostics.pushUndelayed()),
|
||||||
SavedCXXThisTypeOverride(S.CXXThisTypeOverride)
|
SavedCXXThisTypeOverride(S.CXXThisTypeOverride)
|
||||||
{
|
{
|
||||||
assert(ContextToPush && "pushing null context");
|
assert(ContextToPush && "pushing null context");
|
||||||
|
@ -466,7 +437,7 @@ public:
|
||||||
void pop() {
|
void pop() {
|
||||||
if (!SavedContext) return;
|
if (!SavedContext) return;
|
||||||
S.CurContext = SavedContext;
|
S.CurContext = SavedContext;
|
||||||
S.DelayedDiagnostics.popContext(SavedContextState);
|
S.DelayedDiagnostics.popUndelayed(SavedContextState);
|
||||||
S.CXXThisTypeOverride = SavedCXXThisTypeOverride;
|
S.CXXThisTypeOverride = SavedCXXThisTypeOverride;
|
||||||
SavedContext = 0;
|
SavedContext = 0;
|
||||||
}
|
}
|
||||||
|
@ -2608,19 +2579,17 @@ public:
|
||||||
void DiagnoseEmptyLoopBody(const Stmt *S,
|
void DiagnoseEmptyLoopBody(const Stmt *S,
|
||||||
const Stmt *PossibleBody);
|
const Stmt *PossibleBody);
|
||||||
|
|
||||||
ParsingDeclState PushParsingDeclaration() {
|
ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) {
|
||||||
return DelayedDiagnostics.pushParsingDecl();
|
return DelayedDiagnostics.push(pool);
|
||||||
}
|
|
||||||
void PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
|
|
||||||
DelayedDiagnostics::popParsingDecl(*this, state, decl);
|
|
||||||
}
|
}
|
||||||
|
void PopParsingDeclaration(ParsingDeclState state, Decl *decl);
|
||||||
|
|
||||||
typedef ProcessingContextState ParsingClassState;
|
typedef ProcessingContextState ParsingClassState;
|
||||||
ParsingClassState PushParsingClass() {
|
ParsingClassState PushParsingClass() {
|
||||||
return DelayedDiagnostics.pushContext();
|
return DelayedDiagnostics.pushUndelayed();
|
||||||
}
|
}
|
||||||
void PopParsingClass(ParsingClassState state) {
|
void PopParsingClass(ParsingClassState state) {
|
||||||
DelayedDiagnostics.popContext(state);
|
DelayedDiagnostics.popUndelayed(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitDeprecationWarning(NamedDecl *D, StringRef Message,
|
void EmitDeprecationWarning(NamedDecl *D, StringRef Message,
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "clang/Sema/DeclSpec.h"
|
#include "clang/Sema/DeclSpec.h"
|
||||||
#include "clang/Sema/Scope.h"
|
#include "clang/Sema/Scope.h"
|
||||||
#include "clang/AST/DeclTemplate.h"
|
#include "clang/AST/DeclTemplate.h"
|
||||||
|
#include "RAIIObjectsForParser.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
/// ParseCXXInlineMethodDef - We parsed and verified that the specified
|
/// ParseCXXInlineMethodDef - We parsed and verified that the specified
|
||||||
|
|
|
@ -2560,7 +2560,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) {
|
||||||
bool FirstDeclarator = true;
|
bool FirstDeclarator = true;
|
||||||
SourceLocation CommaLoc;
|
SourceLocation CommaLoc;
|
||||||
while (1) {
|
while (1) {
|
||||||
ParsingDeclRAIIObject PD(*this);
|
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
|
||||||
FieldDeclarator DeclaratorInfo(DS);
|
FieldDeclarator DeclaratorInfo(DS);
|
||||||
DeclaratorInfo.D.setCommaLoc(CommaLoc);
|
DeclaratorInfo.D.setCommaLoc(CommaLoc);
|
||||||
|
|
||||||
|
@ -3067,7 +3067,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
|
||||||
|
|
||||||
SourceLocation EqualLoc;
|
SourceLocation EqualLoc;
|
||||||
ExprResult AssignedVal;
|
ExprResult AssignedVal;
|
||||||
ParsingDeclRAIIObject PD(*this);
|
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
|
||||||
|
|
||||||
if (Tok.is(tok::equal)) {
|
if (Tok.is(tok::equal)) {
|
||||||
EqualLoc = ConsumeToken();
|
EqualLoc = ConsumeToken();
|
||||||
|
|
|
@ -965,7 +965,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
|
||||||
tok::TokenKind mType,
|
tok::TokenKind mType,
|
||||||
tok::ObjCKeywordKind MethodImplKind,
|
tok::ObjCKeywordKind MethodImplKind,
|
||||||
bool MethodDefinition) {
|
bool MethodDefinition) {
|
||||||
ParsingDeclRAIIObject PD(*this);
|
ParsingDeclRAIIObject PD(*this, ParsingDeclRAIIObject::NoParent);
|
||||||
|
|
||||||
if (Tok.is(tok::code_completion)) {
|
if (Tok.is(tok::code_completion)) {
|
||||||
Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus,
|
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
|
// Tell the action that names should be checked in the context of
|
||||||
// the declaration to come.
|
// the declaration to come.
|
||||||
ParsingDeclRAIIObject ParsingTemplateParams(*this);
|
ParsingDeclRAIIObject
|
||||||
|
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
|
||||||
|
|
||||||
// Parse multiple levels of template headers within this template
|
// Parse multiple levels of template headers within this template
|
||||||
// parameter scope, e.g.,
|
// parameter scope, e.g.,
|
||||||
|
@ -213,10 +214,11 @@ Parser::ParseSingleDeclarationAfterTemplate(
|
||||||
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
|
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
|
||||||
prefixAttrs);
|
prefixAttrs);
|
||||||
|
|
||||||
// Parse the declaration specifiers, stealing the accumulated
|
// Parse the declaration specifiers, stealing any diagnostics from
|
||||||
// diagnostics from the template parameters.
|
// the template parameters.
|
||||||
ParsingDeclSpec DS(*this, &DiagsFromTParams);
|
ParsingDeclSpec DS(*this, &DiagsFromTParams);
|
||||||
|
|
||||||
|
// Move the attributes from the prefix into the DS.
|
||||||
DS.takeAttributesFrom(prefixAttrs);
|
DS.takeAttributesFrom(prefixAttrs);
|
||||||
|
|
||||||
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
|
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
|
||||||
|
@ -1132,7 +1134,8 @@ Decl *Parser::ParseExplicitInstantiation(unsigned Context,
|
||||||
SourceLocation &DeclEnd,
|
SourceLocation &DeclEnd,
|
||||||
AccessSpecifier AS) {
|
AccessSpecifier AS) {
|
||||||
// This isn't really required here.
|
// This isn't really required here.
|
||||||
ParsingDeclRAIIObject ParsingTemplateParams(*this);
|
ParsingDeclRAIIObject
|
||||||
|
ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent);
|
||||||
|
|
||||||
return ParseSingleDeclarationAfterTemplate(Context,
|
return ParseSingleDeclarationAfterTemplate(Context,
|
||||||
ParsedTemplateInfo(ExternLoc,
|
ParsedTemplateInfo(ExternLoc,
|
||||||
|
|
|
@ -16,13 +16,156 @@
|
||||||
#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
|
#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H
|
||||||
|
|
||||||
#include "clang/Parse/ParseDiagnostic.h"
|
#include "clang/Parse/ParseDiagnostic.h"
|
||||||
|
#include "clang/Parse/Parser.h"
|
||||||
|
#include "clang/Sema/DelayedDiagnostic.h"
|
||||||
|
#include "clang/Sema/Sema.h"
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
// TODO: move ParsingDeclRAIIObject here.
|
|
||||||
// TODO: move ParsingClassDefinition here.
|
// TODO: move ParsingClassDefinition here.
|
||||||
// TODO: move TentativeParsingAction 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
|
/// ExtensionRAIIObject - This saves the state of extension warnings when
|
||||||
/// constructed and disables them. When destructed, it restores them back to
|
/// 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
|
/// the way they used to be. This is used to handle __extension__ in the
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallSet.h"
|
#include "llvm/ADT/SmallSet.h"
|
||||||
#include "llvm/ADT/APFloat.h"
|
#include "llvm/ADT/APFloat.h"
|
||||||
|
#include "llvm/Support/CrashRecoveryContext.h"
|
||||||
#include "clang/Sema/CXXFieldCollector.h"
|
#include "clang/Sema/CXXFieldCollector.h"
|
||||||
#include "clang/Sema/TemplateDeduction.h"
|
#include "clang/Sema/TemplateDeduction.h"
|
||||||
#include "clang/Sema/ExternalSemaSource.h"
|
#include "clang/Sema/ExternalSemaSource.h"
|
||||||
|
@ -201,7 +202,6 @@ Sema::~Sema() {
|
||||||
ExternalSema->ForgetSema();
|
ExternalSema->ForgetSema();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// makeUnavailableInSystemHeader - There is an error in the current
|
/// makeUnavailableInSystemHeader - There is an error in the current
|
||||||
/// context. If we're still in a system header, and we can plausibly
|
/// context. If we're still in a system header, and we can plausibly
|
||||||
/// make the relevant declaration unavailable instead of erroring, do
|
/// 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
|
/// translation unit when EOF is reached and all but the top-level scope is
|
||||||
/// popped.
|
/// popped.
|
||||||
void Sema::ActOnEndOfTranslationUnit() {
|
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
|
// Only complete translation units define vtables and perform implicit
|
||||||
// instantiations.
|
// instantiations.
|
||||||
if (TUKind == TU_Complete) {
|
if (TUKind == TU_Complete) {
|
||||||
|
|
|
@ -4198,57 +4198,30 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
|
||||||
diag.Triggered = true;
|
diag.Triggered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This duplicates a vector push_back but hides the need to know the
|
void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
|
||||||
// size of the type.
|
assert(DelayedDiagnostics.getCurrentPool());
|
||||||
void Sema::DelayedDiagnostics::add(const DelayedDiagnostic &diag) {
|
sema::DelayedDiagnosticPool &poppedPool =
|
||||||
assert(StackSize <= StackCapacity);
|
*DelayedDiagnostics.getCurrentPool();
|
||||||
|
DelayedDiagnostics.popWithoutEmitting(state);
|
||||||
|
|
||||||
// Grow the stack if necessary.
|
// When delaying diagnostics to run in the context of a parsed
|
||||||
if (StackSize == StackCapacity) {
|
// declaration, we only want to actually emit anything if parsing
|
||||||
unsigned newCapacity = 2 * StackCapacity + 2;
|
// succeeds.
|
||||||
char *newBuffer = new char[newCapacity * sizeof(DelayedDiagnostic)];
|
if (!decl) return;
|
||||||
const char *oldBuffer = (const char*) Stack;
|
|
||||||
|
|
||||||
if (StackCapacity)
|
// We emit all the active diagnostics in this pool or any of its
|
||||||
memcpy(newBuffer, oldBuffer, StackCapacity * sizeof(DelayedDiagnostic));
|
// parents. In general, we'll get one pool for the decl spec
|
||||||
|
// and a child pool for each declarator; in a decl group like:
|
||||||
delete[] oldBuffer;
|
// deprecated_typedef foo, *bar, baz();
|
||||||
Stack = reinterpret_cast<sema::DelayedDiagnostic*>(newBuffer);
|
// only the declarator pops will be passed decls. This is correct;
|
||||||
StackCapacity = newCapacity;
|
// we really do need to consider delayed diagnostics from the decl spec
|
||||||
}
|
// for each of the different declarations.
|
||||||
|
const sema::DelayedDiagnosticPool *pool = &poppedPool;
|
||||||
assert(StackSize < StackCapacity);
|
do {
|
||||||
new (&Stack[StackSize++]) DelayedDiagnostic(diag);
|
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.
|
||||||
void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
|
DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i);
|
||||||
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];
|
|
||||||
if (diag.Triggered)
|
if (diag.Triggered)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -4256,25 +4229,19 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state,
|
||||||
case DelayedDiagnostic::Deprecation:
|
case DelayedDiagnostic::Deprecation:
|
||||||
// Don't bother giving deprecation diagnostics if the decl is invalid.
|
// Don't bother giving deprecation diagnostics if the decl is invalid.
|
||||||
if (!decl->isInvalidDecl())
|
if (!decl->isInvalidDecl())
|
||||||
S.HandleDelayedDeprecationCheck(diag, decl);
|
HandleDelayedDeprecationCheck(diag, decl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DelayedDiagnostic::Access:
|
case DelayedDiagnostic::Access:
|
||||||
S.HandleDelayedAccessCheck(diag, decl);
|
HandleDelayedAccessCheck(diag, decl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DelayedDiagnostic::ForbiddenType:
|
case DelayedDiagnostic::ForbiddenType:
|
||||||
handleDelayedForbiddenType(S, diag, decl);
|
handleDelayedForbiddenType(*this, diag, decl);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while ((pool = pool->getParent()));
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isDeclDeprecated(Decl *D) {
|
static bool isDeclDeprecated(Decl *D) {
|
||||||
|
|
Loading…
Reference in New Issue