diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -97,6 +97,7 @@ 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/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -989,6 +989,14 @@ return this->visit(E->getFunctionName()); } +template +bool ByteCodeExprGen::VisitCXXThrowExpr(const CXXThrowExpr *E) { + if (!this->discard(E->getSubExpr())) + return false; + + return this->emitInvalid(E); +} + template bool ByteCodeExprGen::discard(const Expr *E) { if (E->containsErrors()) return false; diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -67,6 +67,7 @@ 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/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -243,6 +243,9 @@ return visitCaseStmt(cast(S)); case Stmt::DefaultStmtClass: return visitDefaultStmt(cast(S)); + case Stmt::GCCAsmStmtClass: + case Stmt::MSAsmStmtClass: + return visitAsmStmt(cast(S)); case Stmt::NullStmtClass: return true; default: { @@ -617,6 +620,11 @@ return this->visitStmt(S->getSubStmt()); } +template +bool ByteCodeStmtGen::visitAsmStmt(const AsmStmt *S) { + return this->emitInvalid(S); +} + namespace clang { namespace interp { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1734,6 +1734,14 @@ 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 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -601,3 +601,6 @@ 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 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -325,7 +325,8 @@ 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 @@ 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 --- /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; + } +}