Index: clang/lib/AST/Interp/ByteCodeExprGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.h +++ 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; Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1102,6 +1102,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; Index: clang/lib/AST/Interp/ByteCodeStmtGen.h =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.h +++ 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); Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ 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 { Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -1823,6 +1823,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 //===----------------------------------------------------------------------===// Index: clang/lib/AST/Interp/Opcodes.td =================================================================== --- clang/lib/AST/Interp/Opcodes.td +++ clang/lib/AST/Interp/Opcodes.td @@ -627,3 +627,6 @@ let Types = [AllTypeClass]; let HasGroup = 1; } + +// [] -> [] +def Invalid : Opcode {} Index: clang/test/AST/Interp/records.cpp =================================================================== --- clang/test/AST/Interp/records.cpp +++ clang/test/AST/Interp/records.cpp @@ -328,7 +328,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}} @@ -336,7 +337,9 @@ 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()'}} \ Index: clang/test/AST/Interp/unsupported.cpp =================================================================== --- /dev/null +++ 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; + } +}