Author: Timm Bäder Date: 2023-07-26T08:59:53+02:00 New Revision: 7d876c62a306fe09a69a5a923c757d2cae305d0c
URL: https://github.com/llvm/llvm-project/commit/7d876c62a306fe09a69a5a923c757d2cae305d0c DIFF: https://github.com/llvm/llvm-project/commit/7d876c62a306fe09a69a5a923c757d2cae305d0c.diff LOG: [clang][Interp] Add 'Invalid' opcode and use it for throw stmts We will use this opcode for conditionally executed statements that are invalid in a constant expression. Differential Revision: https://reviews.llvm.org/D150364 Added: clang/test/AST/Interp/unsupported.cpp Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/lib/AST/Interp/ByteCodeStmtGen.cpp clang/lib/AST/Interp/ByteCodeStmtGen.h clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/records.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index ff40fd3da13f76..bd8e3304c5893b 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -989,6 +989,14 @@ bool ByteCodeExprGen<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) { return this->visit(E->getFunctionName()); } +template <class Emitter> +bool ByteCodeExprGen<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) { + if (!this->discard(E->getSubExpr())) + return false; + + return this->emitInvalid(E); +} + template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) { if (E->containsErrors()) return false; diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index a031aaa9fae1dd..6e29bc32ba3830 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -97,6 +97,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, bool VisitTypeTraitExpr(const TypeTraitExpr *E); bool VisitLambdaExpr(const LambdaExpr *E); bool VisitPredefinedExpr(const PredefinedExpr *E); + bool VisitCXXThrowExpr(const CXXThrowExpr *E); protected: bool visitExpr(const Expr *E) override; diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index 59ef19be356a67..e5ca5c2ae4c33b 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -243,6 +243,9 @@ bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) { return visitCaseStmt(cast<CaseStmt>(S)); case Stmt::DefaultStmtClass: return visitDefaultStmt(cast<DefaultStmt>(S)); + case Stmt::GCCAsmStmtClass: + case Stmt::MSAsmStmtClass: + return visitAsmStmt(cast<AsmStmt>(S)); case Stmt::NullStmtClass: return true; default: { @@ -617,6 +620,11 @@ bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) { return this->visitStmt(S->getSubStmt()); } +template <class Emitter> +bool ByteCodeStmtGen<Emitter>::visitAsmStmt(const AsmStmt *S) { + return this->emitInvalid(S); +} + namespace clang { namespace interp { diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h index bc50b977a6d04f..278e804a803c95 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -67,6 +67,7 @@ class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> { bool visitSwitchStmt(const SwitchStmt *S); bool visitCaseStmt(const CaseStmt *S); bool visitDefaultStmt(const DefaultStmt *S); + bool visitAsmStmt(const AsmStmt *S); bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 87bcf8130a73b3..8a17322ba6ca55 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1734,6 +1734,14 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) { return true; } +/// Just emit a diagnostic. The expression that caused emission of this +/// op is not valid in a constant context. +inline bool Invalid(InterpState &S, CodePtr OpPC) { + const SourceLocation &Loc = S.Current->getLocation(OpPC); + S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); + return false; +} + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 28074a350d05fb..bc81dfedfc6353 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -601,3 +601,6 @@ def Dup : Opcode { let Types = [AllTypeClass]; let HasGroup = 1; } + +// [] -> [] +def Invalid : Opcode {} diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index b708f5f6a00911..46939fb6d072fa 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -325,7 +325,8 @@ namespace InitializerTemporaries { struct S { constexpr S() {} constexpr ~S() noexcept(false) { throw 12; } // expected-error {{cannot use 'throw'}} \ - // expected-note {{declared here}} \ + // expected-error {{never produces a constant expression}} \ + // expected-note 2{{subexpression not valid}} \ // ref-error {{cannot use 'throw'}} \ // ref-error {{never produces a constant expression}} \ // ref-note 2{{subexpression not valid}} @@ -333,7 +334,8 @@ namespace InitializerTemporaries { constexpr int f() { S{}; // ref-note {{in call to 'S{}.~S()'}} - return 12; // expected-note {{undefined function '~S'}} + /// FIXME: Wrong source location below. + return 12; // expected-note {{in call to '&S{}->~S()'}} } static_assert(f() == 12); // expected-error {{not an integral constant expression}} \ // expected-note {{in call to 'f()'}} \ diff --git a/clang/test/AST/Interp/unsupported.cpp b/clang/test/AST/Interp/unsupported.cpp new file mode 100644 index 00000000000000..0182b33a7fdc42 --- /dev/null +++ b/clang/test/AST/Interp/unsupported.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify %s +// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref %s + +namespace Throw { + + constexpr int ConditionalThrow(bool t) { + if (t) + throw 4; // expected-note {{subexpression not valid in a constant expression}} \ + // ref-note {{subexpression not valid in a constant expression}} + + return 0; + } + + static_assert(ConditionalThrow(false) == 0, ""); + static_assert(ConditionalThrow(true) == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'ConditionalThrow(true)'}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'ConditionalThrow(true)'}} + + constexpr int Throw() { // expected-error {{never produces a constant expression}} \ + // ref-error {{never produces a constant expression}} + throw 5; // expected-note {{subexpression not valid in a constant expression}} \ + // ref-note {{subexpression not valid in a constant expression}} + return 0; + } +} + +namespace Asm { + constexpr int ConditionalAsm(bool t) { + if (t) + asm(""); // expected-note {{subexpression not valid in a constant expression}} \ + // ref-note {{subexpression not valid in a constant expression}} + + return 0; + } + static_assert(ConditionalAsm(false) == 0, ""); + static_assert(ConditionalAsm(true) == 0, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to 'ConditionalAsm(true)'}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to 'ConditionalAsm(true)'}} + + + constexpr int Asm() { // expected-error {{never produces a constant expression}} \ + // ref-error {{never produces a constant expression}} + __asm volatile(""); // expected-note {{subexpression not valid in a constant expression}} \ + // ref-note {{subexpression not valid in a constant expression}} + return 0; + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits