Author: Timm Bäder Date: 2024-03-15T10:52:58+01:00 New Revision: 72d85b0315628c982be21c7aada59b6f9274de90
URL: https://github.com/llvm/llvm-project/commit/72d85b0315628c982be21c7aada59b6f9274de90 DIFF: https://github.com/llvm/llvm-project/commit/72d85b0315628c982be21c7aada59b6f9274de90.diff LOG: [clang][Interp] Emit Error op for contains-error expressions Instead of aborting interpretation right away. This way we can still successfully evaluate such functions provided we don't reach the Error op at all. Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/Interp.h clang/lib/AST/Interp/Opcodes.td clang/test/AST/Interp/if.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 39bacbebb5ba7b..f07e430e279d22 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2244,7 +2244,7 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) { template <class Emitter> bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) { if (E->containsErrors()) - return false; + return this->emitError(E); // We're basically doing: // OptionScope<Emitter> Scope(this, DicardResult, Initializing); @@ -2254,7 +2254,7 @@ bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) { template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) { if (E->containsErrors()) - return false; + return this->emitError(E); if (E->getType()->isVoidType()) return this->discard(E); @@ -2283,7 +2283,7 @@ bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) { assert(!classify(E->getType())); if (E->containsErrors()) - return false; + return this->emitError(E); OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false, /*NewInitializing=*/true); diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 08e272cbc005bd..405993eb827036 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -2227,6 +2227,9 @@ inline bool Invalid(InterpState &S, CodePtr OpPC) { return false; } +/// Do nothing and just abort execution. +inline bool Error(InterpState &S, CodePtr OpPC) { return false; } + /// Same here, but only for casts. inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) { const SourceLocation &Loc = S.Current->getLocation(OpPC); diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 0ed214af3548aa..cc1310f4c0d52a 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -706,6 +706,7 @@ def Dup : Opcode { // [] -> [] def Invalid : Opcode {} +def Error : Opcode {} def InvalidCast : Opcode { let Args = [ArgCastKind]; } diff --git a/clang/test/AST/Interp/if.cpp b/clang/test/AST/Interp/if.cpp index 86ae8de6f73ebb..37289d69d32554 100644 --- a/clang/test/AST/Interp/if.cpp +++ b/clang/test/AST/Interp/if.cpp @@ -1,8 +1,5 @@ -// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify -// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref - -// expected-no-diagnostics -// ref-no-diagnostics +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify=expected,both +// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref,both namespace ConstEval { constexpr int f() { @@ -51,3 +48,13 @@ namespace InitDecl { } static_assert(attrs() == 1, ""); }; + +/// The faulty if statement creates a RecoveryExpr with contains-errors, +/// but the execution will never reach that. +constexpr char g(char const (&x)[2]) { + return 'x'; + if (auto [a, b] = x) // both-error {{an array type is not allowed here}} \ + // both-warning {{ISO C++17 does not permit structured binding declaration in a condition}} + ; +} +static_assert(g("x") == 'x'); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits