Skip to content

Commit 72d85b0

Browse files
committed
[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.
1 parent 8310fd3 commit 72d85b0

File tree

4 files changed

+19
-8
lines changed

4 files changed

+19
-8
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2244,7 +2244,7 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
22442244
template <class Emitter>
22452245
bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) {
22462246
if (E->containsErrors())
2247-
return false;
2247+
return this->emitError(E);
22482248

22492249
// We're basically doing:
22502250
// OptionScope<Emitter> Scope(this, DicardResult, Initializing);
@@ -2254,7 +2254,7 @@ bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) {
22542254

22552255
template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
22562256
if (E->containsErrors())
2257-
return false;
2257+
return this->emitError(E);
22582258

22592259
if (E->getType()->isVoidType())
22602260
return this->discard(E);
@@ -2283,7 +2283,7 @@ bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) {
22832283
assert(!classify(E->getType()));
22842284

22852285
if (E->containsErrors())
2286-
return false;
2286+
return this->emitError(E);
22872287

22882288
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
22892289
/*NewInitializing=*/true);

clang/lib/AST/Interp/Interp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,6 +2227,9 @@ inline bool Invalid(InterpState &S, CodePtr OpPC) {
22272227
return false;
22282228
}
22292229

2230+
/// Do nothing and just abort execution.
2231+
inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
2232+
22302233
/// Same here, but only for casts.
22312234
inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
22322235
const SourceLocation &Loc = S.Current->getLocation(OpPC);

clang/lib/AST/Interp/Opcodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ def Dup : Opcode {
706706

707707
// [] -> []
708708
def Invalid : Opcode {}
709+
def Error : Opcode {}
709710
def InvalidCast : Opcode {
710711
let Args = [ArgCastKind];
711712
}

clang/test/AST/Interp/if.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify
2-
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref
3-
4-
// expected-no-diagnostics
5-
// ref-no-diagnostics
1+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fexperimental-new-constant-interpreter %s -verify=expected,both
2+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only %s -verify=ref,both
63

74
namespace ConstEval {
85
constexpr int f() {
@@ -51,3 +48,13 @@ namespace InitDecl {
5148
}
5249
static_assert(attrs() == 1, "");
5350
};
51+
52+
/// The faulty if statement creates a RecoveryExpr with contains-errors,
53+
/// but the execution will never reach that.
54+
constexpr char g(char const (&x)[2]) {
55+
return 'x';
56+
if (auto [a, b] = x) // both-error {{an array type is not allowed here}} \
57+
// both-warning {{ISO C++17 does not permit structured binding declaration in a condition}}
58+
;
59+
}
60+
static_assert(g("x") == 'x');

0 commit comments

Comments
 (0)