diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 97cd903f3d6f4..258b17e83b881 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -2080,6 +2080,7 @@ class IfStmt final /// If this is an 'if constexpr', determine which substatement will be taken. /// Otherwise, or if the condition is value-dependent, returns None. Optional getNondiscardedCase(const ASTContext &Ctx) const; + Optional getNondiscardedCase(const ASTContext &Ctx); bool isObjCAvailabilityCheck() const; diff --git a/clang/include/clang/Analysis/CallGraph.h b/clang/include/clang/Analysis/CallGraph.h index 999ac5da8acb6..4b4344814ba65 100644 --- a/clang/include/clang/Analysis/CallGraph.h +++ b/clang/include/clang/Analysis/CallGraph.h @@ -29,6 +29,7 @@ namespace clang { +class ASTContext; class CallGraphNode; class Decl; class DeclContext; @@ -51,6 +52,12 @@ class CallGraph : public RecursiveASTVisitor { /// This is a virtual root node that has edges to all the functions. CallGraphNode *Root; + /// A setting to determine whether this should include calls that are done in + /// a constant expression's context. This DOES require the ASTContext object + /// for constexpr-if, so setting it requires a valid ASTContext. + bool shouldSkipConstexpr = false; + ASTContext *Ctx; + public: CallGraph(); ~CallGraph(); @@ -66,7 +73,7 @@ class CallGraph : public RecursiveASTVisitor { /// Determine if a declaration should be included in the graph. static bool includeInGraph(const Decl *D); - /// Determine if a declaration should be included in the graph for the + /// Determine if a declaration should be included in the graph for the /// purposes of being a callee. This is similar to includeInGraph except /// it permits declarations, not just definitions. static bool includeCalleeInGraph(const Decl *D); @@ -138,6 +145,16 @@ class CallGraph : public RecursiveASTVisitor { bool shouldWalkTypesOfTypeLocs() const { return false; } bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return true; } + bool shouldVisitConstantExpressions() const { return false; } + bool shouldSkipConstantExpressions() const { return shouldSkipConstexpr; } + void setSkipConstantExpressions(ASTContext &Context) { + Ctx = &Context; + shouldSkipConstexpr = true; + } + ASTContext &getASTContext() { + assert(Ctx); + return *Ctx; + } private: /// Add the given declaration to the call graph. diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 2ceee614cf98f..8073d7bec19d8 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -995,6 +995,12 @@ Optional IfStmt::getNondiscardedCase(const ASTContext &Ctx) const { return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen(); } +Optional IfStmt::getNondiscardedCase(const ASTContext &Ctx) { + if (!isConstexpr() || getCond()->isValueDependent()) + return None; + return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen(); +} + ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP) diff --git a/clang/lib/Analysis/CallGraph.cpp b/clang/lib/Analysis/CallGraph.cpp index 2299ba32db501..78197ea5e65c2 100644 --- a/clang/lib/Analysis/CallGraph.cpp +++ b/clang/lib/Analysis/CallGraph.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/CallGraph.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" @@ -136,6 +137,37 @@ class CGBuilder : public StmtVisitor { } } + void VisitIfStmt(IfStmt *If) { + if (G->shouldSkipConstantExpressions()) { + if (llvm::Optional ActiveStmt = + If->getNondiscardedCase(G->getASTContext())) { + if (*ActiveStmt) + this->Visit(*ActiveStmt); + return; + } + } + + StmtVisitor::VisitIfStmt(If); + } + + void VisitDeclStmt(DeclStmt *DS) { + if (G->shouldSkipConstantExpressions()) { + auto IsConstexprVarDecl = [](Decl *D) { + if (const auto *VD = dyn_cast(D)) + return VD->isConstexpr(); + return false; + }; + if (llvm::any_of(DS->decls(), IsConstexprVarDecl)) { + assert(llvm::all_of(DS->decls(), IsConstexprVarDecl) && + "Situation where a decl-group would be a mix of decl types, or " + "constexpr and not?"); + return; + } + } + + StmtVisitor::VisitDeclStmt(DS); + } + void VisitChildren(Stmt *S) { for (Stmt *SubStmt : S->children()) if (SubStmt) diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 7cfb5bdbc5b7a..32c5584ecf4c9 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -548,6 +548,7 @@ class DeviceFunctionTracker { public: DeviceFunctionTracker(Sema &S) : SemaRef(S) { + CG.setSkipConstantExpressions(S.Context); CG.addToCallGraph(S.getASTContext().getTranslationUnitDecl()); CollectSyclExternalFuncs(); }