[clang] 0dcada9 - [clang][Interp] Fix array subscript eval order (#101804)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 3 03:25:24 PDT 2024
Author: Timm Baeder
Date: 2024-08-03T12:25:20+02:00
New Revision: 0dcada94bb1ae79f0edd91013038098c62a96b3b
URL: https://github.com/llvm/llvm-project/commit/0dcada94bb1ae79f0edd91013038098c62a96b3b
DIFF: https://github.com/llvm/llvm-project/commit/0dcada94bb1ae79f0edd91013038098c62a96b3b.diff
LOG: [clang][Interp] Fix array subscript eval order (#101804)
Always evaluate LHS first, then RHS.
Added:
Modified:
clang/lib/AST/Interp/Compiler.cpp
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/Opcodes.td
clang/test/AST/Interp/eval-order.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index f600d9b5b80f8..e1fa0eb1eacb3 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -1282,21 +1282,31 @@ bool Compiler<Emitter>::VisitImplicitValueInitExpr(
template <class Emitter>
bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
- const Expr *Base = E->getBase();
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
const Expr *Index = E->getIdx();
if (DiscardResult)
- return this->discard(Base) && this->discard(Index);
+ return this->discard(LHS) && this->discard(RHS);
- // Take pointer of LHS, add offset from RHS.
- // What's left on the stack after this is a pointer.
- if (!this->visit(Base))
- return false;
+ // C++17's rules require us to evaluate the LHS first, regardless of which
+ // side is the base.
+ bool Success = true;
+ for (const Expr *SubExpr : {LHS, RHS}) {
+ if (!this->visit(SubExpr))
+ Success = false;
+ }
- if (!this->visit(Index))
+ if (!Success)
return false;
PrimType IndexT = classifyPrim(Index->getType());
+ // If the index is first, we need to change that.
+ if (LHS == Index) {
+ if (!this->emitFlip(PT_Ptr, IndexT, E))
+ return false;
+ }
+
return this->emitArrayElemPtrPop(IndexT, E);
}
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index b54635b9988e2..a3f81e2de466b 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1158,6 +1158,21 @@ bool Pop(InterpState &S, CodePtr OpPC) {
return true;
}
+/// [Value1, Value2] -> [Value2, Value1]
+template <PrimType TopName, PrimType BottomName>
+bool Flip(InterpState &S, CodePtr OpPC) {
+ using TopT = typename PrimConv<TopName>::T;
+ using BottomT = typename PrimConv<BottomName>::T;
+
+ const auto &Top = S.Stk.pop<TopT>();
+ const auto &Bottom = S.Stk.pop<BottomT>();
+
+ S.Stk.push<TopT>(Top);
+ S.Stk.push<BottomT>(Bottom);
+
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Const
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 3e830f89754dc..70d06bdfdc21c 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -729,6 +729,11 @@ def Dup : Opcode {
let HasGroup = 1;
}
+def Flip : Opcode {
+ let Types = [AllTypeClass, AllTypeClass];
+ let HasGroup = 1;
+}
+
// [] -> []
def Invalid : Opcode {}
def Unsupported : Opcode {}
diff --git a/clang/test/AST/Interp/eval-order.cpp b/clang/test/AST/Interp/eval-order.cpp
index 7a7ce6a714601..77f50831f4f47 100644
--- a/clang/test/AST/Interp/eval-order.cpp
+++ b/clang/test/AST/Interp/eval-order.cpp
@@ -45,7 +45,7 @@ namespace EvalOrder {
}
template <typename T> constexpr T &&b(T &&v) {
if (!done_a)
- throw "wrong"; // expected-note 7{{not valid}}
+ throw "wrong"; // expected-note 5{{not valid}}
done_b = true;
return (T &&)v;
}
@@ -95,10 +95,9 @@ namespace EvalOrder {
constexpr int arr[3] = {};
SEQ(A(arr)[B(0)]);
SEQ(A(+arr)[B(0)]);
- SEQ(A(0)[B(arr)]); // expected-error {{not an integral constant expression}} FIXME \
- // expected-note 2{{in call to}}
- SEQ(A(0)[B(+arr)]); // expected-error {{not an integral constant expression}} FIXME \
- // expected-note 2{{in call to}}
+ SEQ(A(0)[B(arr)]);
+ SEQ(A(0)[B(+arr)]);
+
SEQ(A(ud)[B(0)]);
// Rule 7: a << b
More information about the cfe-commits
mailing list