[clang] 08ba9ce - Suppress Deferred Diagnostics in discarded statements.
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Wed May 12 12:48:52 PDT 2021
Author: Erich Keane
Date: 2021-05-12T12:48:47-07:00
New Revision: 08ba9ce1ef7214623d4104e72d817c73644a0884
URL: https://github.com/llvm/llvm-project/commit/08ba9ce1ef7214623d4104e72d817c73644a0884
DIFF: https://github.com/llvm/llvm-project/commit/08ba9ce1ef7214623d4104e72d817c73644a0884.diff
LOG: Suppress Deferred Diagnostics in discarded statements.
It doesn't really make sense to emit language specific diagnostics
in a discarded statement, and suppressing these diagnostics results in a
programming pattern that many users will feel is quite useful.
Basically, this makes sure we only emit errors from the 'true' side of a
'constexpr if'.
It does this by making the ExprEvaluatorBase type have an opt-in option
as to whether it should visit discarded cases.
Differential Revision: https://reviews.llvm.org/D102251
Added:
Modified:
clang/include/clang/AST/EvaluatedExprVisitor.h
clang/include/clang/AST/Stmt.h
clang/lib/AST/Stmt.cpp
clang/lib/Sema/Sema.cpp
clang/test/SemaCUDA/deferred-diags.cu
Removed:
################################################################################
diff --git a/clang/include/clang/AST/EvaluatedExprVisitor.h b/clang/include/clang/AST/EvaluatedExprVisitor.h
index 2f6c314b41119..2991f2859ac4e 100644
--- a/clang/include/clang/AST/EvaluatedExprVisitor.h
+++ b/clang/include/clang/AST/EvaluatedExprVisitor.h
@@ -32,6 +32,9 @@ class EvaluatedExprVisitorBase : public StmtVisitorBase<Ptr, ImplClass, void> {
const ASTContext &Context;
public:
+ // Return whether this visitor should recurse into discarded statements for a
+ // 'constexpr-if'.
+ bool shouldVisitDiscardedStmt() const { return true; }
#define PTR(CLASS) typename Ptr<CLASS>::type
explicit EvaluatedExprVisitorBase(const ASTContext &Context) : Context(Context) { }
@@ -83,7 +86,7 @@ class EvaluatedExprVisitorBase : public StmtVisitorBase<Ptr, ImplClass, void> {
void VisitCallExpr(PTR(CallExpr) CE) {
if (!CE->isUnevaluatedBuiltinCall(Context))
- return static_cast<ImplClass*>(this)->VisitExpr(CE);
+ return getDerived().VisitExpr(CE);
}
void VisitLambdaExpr(PTR(LambdaExpr) LE) {
@@ -103,6 +106,20 @@ class EvaluatedExprVisitorBase : public StmtVisitorBase<Ptr, ImplClass, void> {
this->Visit(SubStmt);
}
+ void VisitIfStmt(PTR(IfStmt) If) {
+ if (!getDerived().shouldVisitDiscardedStmt()) {
+ if (auto SubStmt = If->getNondiscardedCase(Context)) {
+ if (*SubStmt)
+ this->Visit(*SubStmt);
+ return;
+ }
+ }
+
+ getDerived().VisitStmt(If);
+ }
+
+ ImplClass &getDerived() { return *static_cast<ImplClass *>(this); }
+
#undef PTR
};
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<const Stmt*> getNondiscardedCase(const ASTContext &Ctx) const;
+ Optional<Stmt *> getNondiscardedCase(const ASTContext &Ctx);
bool isObjCAvailabilityCheck() const;
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 2ceee614cf98f..d30df296dbd57 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -989,12 +989,20 @@ bool IfStmt::isObjCAvailabilityCheck() const {
return isa<ObjCAvailabilityCheckExpr>(getCond());
}
-Optional<const Stmt*> IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
+Optional<Stmt *> IfStmt::getNondiscardedCase(const ASTContext &Ctx) {
if (!isConstexpr() || getCond()->isValueDependent())
return None;
return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen();
}
+Optional<const Stmt *>
+IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
+ if (Optional<Stmt *> Result =
+ const_cast<IfStmt *>(this)->getNondiscardedCase(Ctx))
+ return *Result;
+ return None;
+}
+
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/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index b23140b4589c3..72e2ee613cbf4 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1569,6 +1569,8 @@ class DeferredDiagnosticsEmitter
DeferredDiagnosticsEmitter(Sema &S)
: Inherited(S), ShouldEmitRootNode(false), InOMPDeviceContext(0) {}
+ bool shouldVisitDiscardedStmt() const { return false; }
+
void VisitOMPTargetDirective(OMPTargetDirective *Node) {
++InOMPDeviceContext;
Inherited::VisitOMPTargetDirective(Node);
diff --git a/clang/test/SemaCUDA/deferred-diags.cu b/clang/test/SemaCUDA/deferred-diags.cu
index 856a5e06a58ff..125ddea95b996 100644
--- a/clang/test/SemaCUDA/deferred-diags.cu
+++ b/clang/test/SemaCUDA/deferred-diags.cu
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fcxx-exceptions -fcuda-is-device -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -fcuda-is-device -fsyntax-only -std=c++17 -verify %s
#include "Inputs/cuda.h"
@@ -8,29 +8,55 @@ inline __host__ __device__ void hasInvalid() {
// expected-error at -1 2{{cannot use 'throw' in __host__ __device__ function}}
}
+inline __host__ __device__ void hasInvalid2() {
+ throw NULL;
+ // expected-error at -1 2{{cannot use 'throw' in __host__ __device__ function}}
+}
+
+inline __host__ __device__ void hasInvalidDiscarded() {
+ // This is only used in the discarded statements below, so this should not diagnose.
+ throw NULL;
+}
+
static __device__ void use0() {
hasInvalid(); // expected-note {{called by 'use0'}}
hasInvalid(); // expected-note {{called by 'use0'}}
+
+ if constexpr (true) {
+ hasInvalid2(); // expected-note {{called by 'use0'}}
+ } else {
+ hasInvalidDiscarded();
+ }
+
+ if constexpr (false) {
+ hasInvalidDiscarded();
+ } else {
+ hasInvalid2(); // expected-note {{called by 'use0'}}
+ }
+
+ if constexpr (false) {
+ hasInvalidDiscarded();
+ }
}
// To avoid excessive diagnostic messages, deferred diagnostics are only
// emitted the first time a function is called.
static __device__ void use1() {
- use0(); // expected-note 2{{called by 'use1'}}
+ use0(); // expected-note 4{{called by 'use1'}}
use0();
}
static __device__ void use2() {
- use1(); // expected-note 2{{called by 'use2'}}
+ use1(); // expected-note 4{{called by 'use2'}}
use1();
}
static __device__ void use3() {
- use2(); // expected-note 2{{called by 'use3'}}
+ use2(); // expected-note 4{{called by 'use3'}}
use2();
}
__global__ void use4() {
- use3(); // expected-note 2{{called by 'use4'}}
+ use3(); // expected-note 4{{called by 'use4'}}
use3();
}
More information about the cfe-commits
mailing list