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@-1 2{{cannot use 'throw' in __host__ __device__ function}} } +inline __host__ __device__ void hasInvalid2() { + throw NULL; + // expected-error@-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(); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits