Skip to content

Commit

Permalink
[clang][Interp] Emit Error op for contains-error expressions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tbaederr committed Mar 15, 2024
1 parent 8310fd3 commit 72d85b0
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 8 deletions.
6 changes: 3 additions & 3 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ def Dup : Opcode {

// [] -> []
def Invalid : Opcode {}
def Error : Opcode {}
def InvalidCast : Opcode {
let Args = [ArgCastKind];
}
Expand Down
17 changes: 12 additions & 5 deletions clang/test/AST/Interp/if.cpp
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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');

0 comments on commit 72d85b0

Please sign in to comment.