add ConstEvaluatedExprVisitor

Differential Revision: http://reviews.llvm.org/D10210

llvm-svn: 239474
This commit is contained in:
Scott Douglass 2015-06-10 13:53:15 +00:00
parent 965bf6a3ce
commit 503fc39d1f
6 changed files with 77 additions and 55 deletions

View File

@ -26,29 +26,31 @@ class ASTContext;
/// \brief Given a potentially-evaluated expression, this visitor visits all
/// of its potentially-evaluated subexpressions, recursively.
template<typename ImplClass>
class EvaluatedExprVisitor : public StmtVisitor<ImplClass> {
ASTContext &Context;
template<template <typename> class Ptr, typename ImplClass>
class EvaluatedExprVisitorBase : public StmtVisitorBase<Ptr, ImplClass, void> {
const ASTContext &Context;
public:
explicit EvaluatedExprVisitor(ASTContext &Context) : Context(Context) { }
#define PTR(CLASS) typename Ptr<CLASS>::type
explicit EvaluatedExprVisitorBase(const ASTContext &Context) : Context(Context) { }
// Expressions that have no potentially-evaluated subexpressions (but may have
// other sub-expressions).
void VisitDeclRefExpr(DeclRefExpr *E) { }
void VisitOffsetOfExpr(OffsetOfExpr *E) { }
void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { }
void VisitExpressionTraitExpr(ExpressionTraitExpr *E) { }
void VisitBlockExpr(BlockExpr *E) { }
void VisitCXXUuidofExpr(CXXUuidofExpr *E) { }
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { }
void VisitMemberExpr(MemberExpr *E) {
void VisitDeclRefExpr(PTR(DeclRefExpr) E) { }
void VisitOffsetOfExpr(PTR(OffsetOfExpr) E) { }
void VisitUnaryExprOrTypeTraitExpr(PTR(UnaryExprOrTypeTraitExpr) E) { }
void VisitExpressionTraitExpr(PTR(ExpressionTraitExpr) E) { }
void VisitBlockExpr(PTR(BlockExpr) E) { }
void VisitCXXUuidofExpr(PTR(CXXUuidofExpr) E) { }
void VisitCXXNoexceptExpr(PTR(CXXNoexceptExpr) E) { }
void VisitMemberExpr(PTR(MemberExpr) E) {
// Only the base matters.
return this->Visit(E->getBase());
}
void VisitChooseExpr(ChooseExpr *E) {
void VisitChooseExpr(PTR(ChooseExpr) E) {
// Don't visit either child expression if the condition is dependent.
if (E->getCond()->isValueDependent())
return;
@ -56,7 +58,7 @@ public:
return this->Visit(E->getChosenSubExpr());
}
void VisitGenericSelectionExpr(GenericSelectionExpr *E) {
void VisitGenericSelectionExpr(PTR(GenericSelectionExpr) E) {
// The controlling expression of a generic selection is not evaluated.
// Don't visit either child expression if the condition is type-dependent.
@ -67,23 +69,23 @@ public:
return this->Visit(E->getResultExpr());
}
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
void VisitDesignatedInitExpr(PTR(DesignatedInitExpr) E) {
// Only the actual initializer matters; the designators are all constant
// expressions.
return this->Visit(E->getInit());
}
void VisitCXXTypeidExpr(CXXTypeidExpr *E) {
void VisitCXXTypeidExpr(PTR(CXXTypeidExpr) E) {
if (E->isPotentiallyEvaluated())
return this->Visit(E->getExprOperand());
}
void VisitCallExpr(CallExpr *CE) {
void VisitCallExpr(PTR(CallExpr) CE) {
if (!CE->isUnevaluatedBuiltinCall(Context))
return static_cast<ImplClass*>(this)->VisitExpr(CE);
}
void VisitLambdaExpr(LambdaExpr *LE) {
void VisitLambdaExpr(PTR(LambdaExpr) LE) {
// Only visit the capture initializers, and not the body.
for (LambdaExpr::capture_init_iterator I = LE->capture_init_begin(),
E = LE->capture_init_end();
@ -94,11 +96,31 @@ public:
/// \brief The basis case walks all of the children of the statement or
/// expression, assuming they are all potentially evaluated.
void VisitStmt(Stmt *S) {
for (Stmt::child_range C = S->children(); C; ++C)
void VisitStmt(PTR(Stmt) S) {
for (auto C = S->children(); C; ++C)
if (*C)
this->Visit(*C);
}
#undef PTR
};
/// EvaluatedExprVisitor - This class visits 'Expr *'s
template<typename ImplClass>
class EvaluatedExprVisitor
: public EvaluatedExprVisitorBase<make_ptr, ImplClass> {
public:
explicit EvaluatedExprVisitor(const ASTContext &Context) :
EvaluatedExprVisitorBase<make_ptr, ImplClass>(Context) { }
};
/// ConstEvaluatedExprVisitor - This class visits 'const Expr *'s.
template<typename ImplClass>
class ConstEvaluatedExprVisitor
: public EvaluatedExprVisitorBase<make_const_ptr, ImplClass> {
public:
explicit ConstEvaluatedExprVisitor(const ASTContext &Context) :
EvaluatedExprVisitorBase<make_const_ptr, ImplClass>(Context) { }
};
}

View File

@ -598,7 +598,7 @@ public:
/// \brief Determine whether this expression involves a call to any function
/// that is not trivial.
bool hasNonTrivialCall(ASTContext &Ctx);
bool hasNonTrivialCall(const ASTContext &Ctx) const;
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
/// integer. This must be called on an expression that constant folds to an
@ -2273,7 +2273,7 @@ public:
/// \brief Returns \c true if this is a call to a builtin which does not
/// evaluate side-effects within its arguments.
bool isUnevaluatedBuiltinCall(ASTContext &Ctx) const;
bool isUnevaluatedBuiltinCall(const ASTContext &Ctx) const;
/// getCallReturnType - Get the return type of the call expr. This is not
/// always the type of the expr itself, if the return type is a reference

View File

@ -1238,7 +1238,7 @@ unsigned CallExpr::getBuiltinCallee() const {
return FDecl->getBuiltinID();
}
bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const {
bool CallExpr::isUnevaluatedBuiltinCall(const ASTContext &Ctx) const {
if (unsigned BI = getBuiltinCallee())
return Ctx.BuiltinInfo.isUnevaluated(BI);
return false;
@ -3136,21 +3136,21 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
namespace {
/// \brief Look for a call to a non-trivial function within an expression.
class NonTrivialCallFinder : public EvaluatedExprVisitor<NonTrivialCallFinder>
class NonTrivialCallFinder : public ConstEvaluatedExprVisitor<NonTrivialCallFinder>
{
typedef EvaluatedExprVisitor<NonTrivialCallFinder> Inherited;
typedef ConstEvaluatedExprVisitor<NonTrivialCallFinder> Inherited;
bool NonTrivial;
public:
explicit NonTrivialCallFinder(ASTContext &Context)
explicit NonTrivialCallFinder(const ASTContext &Context)
: Inherited(Context), NonTrivial(false) { }
bool hasNonTrivialCall() const { return NonTrivial; }
void VisitCallExpr(CallExpr *E) {
if (CXXMethodDecl *Method
= dyn_cast_or_null<CXXMethodDecl>(E->getCalleeDecl())) {
void VisitCallExpr(const CallExpr *E) {
if (const CXXMethodDecl *Method
= dyn_cast_or_null<const CXXMethodDecl>(E->getCalleeDecl())) {
if (Method->isTrivial()) {
// Recurse to children of the call.
Inherited::VisitStmt(E);
@ -3160,8 +3160,8 @@ namespace {
NonTrivial = true;
}
void VisitCXXConstructExpr(CXXConstructExpr *E) {
void VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (E->getConstructor()->isTrivial()) {
// Recurse to children of the call.
Inherited::VisitStmt(E);
@ -3170,8 +3170,8 @@ namespace {
NonTrivial = true;
}
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) {
if (E->getTemporary()->getDestructor()->isTrivial()) {
Inherited::VisitStmt(E);
return;
@ -3182,7 +3182,7 @@ namespace {
};
}
bool Expr::hasNonTrivialCall(ASTContext &Ctx) {
bool Expr::hasNonTrivialCall(const ASTContext &Ctx) const {
NonTrivialCallFinder Finder(Ctx);
Finder.Visit(this);
return Finder.hasNonTrivialCall();

View File

@ -370,25 +370,25 @@ namespace {
/// A visitor which checks whether an initializer uses 'this' in a
/// way which requires the vtable to be properly set.
struct DynamicThisUseChecker : EvaluatedExprVisitor<DynamicThisUseChecker> {
typedef EvaluatedExprVisitor<DynamicThisUseChecker> super;
struct DynamicThisUseChecker : ConstEvaluatedExprVisitor<DynamicThisUseChecker> {
typedef ConstEvaluatedExprVisitor<DynamicThisUseChecker> super;
bool UsesThis;
DynamicThisUseChecker(ASTContext &C) : super(C), UsesThis(false) {}
DynamicThisUseChecker(const ASTContext &C) : super(C), UsesThis(false) {}
// Black-list all explicit and implicit references to 'this'.
//
// Do we need to worry about external references to 'this' derived
// from arbitrary code? If so, then anything which runs arbitrary
// external code might potentially access the vtable.
void VisitCXXThisExpr(CXXThisExpr *E) { UsesThis = true; }
void VisitCXXThisExpr(const CXXThisExpr *E) { UsesThis = true; }
};
}
static bool BaseInitializerUsesThis(ASTContext &C, const Expr *Init) {
DynamicThisUseChecker Checker(C);
Checker.Visit(const_cast<Expr*>(Init));
Checker.Visit(Init);
return Checker.UsesThis;
}

View File

@ -574,28 +574,29 @@ namespace {
/// ContainsReference - A visitor class to search for references to
/// a particular declaration (the needle) within any evaluated component of an
/// expression (recursively).
class ContainsReference : public EvaluatedExprVisitor<ContainsReference> {
class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> {
bool FoundReference;
const DeclRefExpr *Needle;
public:
ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)
: EvaluatedExprVisitor<ContainsReference>(Context),
FoundReference(false), Needle(Needle) {}
typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited;
void VisitExpr(Expr *E) {
ContainsReference(ASTContext &Context, const DeclRefExpr *Needle)
: Inherited(Context), FoundReference(false), Needle(Needle) {}
void VisitExpr(const Expr *E) {
// Stop evaluating if we already have a reference.
if (FoundReference)
return;
EvaluatedExprVisitor<ContainsReference>::VisitExpr(E);
Inherited::VisitExpr(E);
}
void VisitDeclRefExpr(DeclRefExpr *E) {
void VisitDeclRefExpr(const DeclRefExpr *E) {
if (E == Needle)
FoundReference = true;
else
EvaluatedExprVisitor<ContainsReference>::VisitDeclRefExpr(E);
Inherited::VisitDeclRefExpr(E);
}
bool doesContainReference() const { return FoundReference; }
@ -854,7 +855,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
return false;
ContainsReference CR(S.Context, DRE);
CR.Visit(const_cast<Expr*>(Initializer));
CR.Visit(Initializer);
if (CR.doesContainReference()) {
S.Diag(DRE->getLocStart(),
diag::warn_uninit_self_reference_in_init)

View File

@ -20,7 +20,6 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"