Skip to content

[clang][Interp] Fix array subscript eval order #101804

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2024
Merged

Conversation

tbaederr
Copy link
Contributor

@tbaederr tbaederr commented Aug 3, 2024

Always evaluate LHS first, then RHS.

Always evaluate LHS first, then RHS.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 3, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 3, 2024

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

Always evaluate LHS first, then RHS.


Full diff: https://github.com/llvm/llvm-project/pull/101804.diff

4 Files Affected:

  • (modified) clang/lib/AST/Interp/Compiler.cpp (+17-7)
  • (modified) clang/lib/AST/Interp/Interp.h (+15)
  • (modified) clang/lib/AST/Interp/Opcodes.td (+5)
  • (modified) clang/test/AST/Interp/eval-order.cpp (+4-5)
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

@tbaederr tbaederr merged commit 0dcada9 into llvm:main Aug 3, 2024
10 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Aug 3, 2024

LLVM Buildbot has detected a new failure on builder sanitizer-windows running on sanitizer-windows while building clang at step 4 "annotate".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/107/builds/1553

Here is the relevant piece of the build log for the reference:

Step 4 (annotate) failure: 'python ../llvm-zorg/zorg/buildbot/builders/annotated/sanitizer-windows.py ...' (failure)
...
[14/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Context.cpp.obj
[15/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\InterpBuiltin.cpp.obj
[16/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Compiler.cpp.obj
[17/26] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\AsmPrinter.cpp.obj
[18/26] Linking CXX static library lib\LLVMAsmPrinter.lib
[19/26] Building CXX object lib\LTO\CMakeFiles\LLVMLTO.dir\LTO.cpp.obj
[20/26] Linking CXX static library lib\LLVMLTO.lib
[21/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\EvalEmitter.cpp.obj
[22/26] Linking CXX executable bin\lld.exe
[23/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Disasm.cpp.obj
command timed out: 1200 seconds without output running ['python', '../llvm-zorg/zorg/buildbot/builders/annotated/sanitizer-windows.py', '--jobs=16'], attempting to kill
program finished with exit code 1
elapsedTime=1268.363000
Step 7 (stage 1 build) failure: stage 1 build (failure)
@@@BUILD_STEP stage 1 build@@@
Running: ninja -j 16 compiler-rt
[1/2] Building CXX object projects\compiler-rt\lib\asan\CMakeFiles\RTAsan_dynamic_version_script_dummy.x86_64.dir\dummy.cpp.obj
[2/2] Linking CXX shared library lib\clang\20\lib\windows\clang_rt.asan_dynamic-x86_64.dll
Running: ninja -j 16 clang lld
[1/26] Building Opcodes.inc...
[2/26] Generating VCSRevision.h
[3/26] Generating VCSVersion.inc
[4/26] Building CXX object tools\clang\lib\Basic\CMakeFiles\obj.clangBasic.dir\Version.cpp.obj
[5/26] Building CXX object lib\Object\CMakeFiles\LLVMObject.dir\IRSymtab.cpp.obj
[6/26] Linking CXX static library lib\LLVMObject.lib
[7/26] Generating VCSVersion.inc
[8/26] Linking CXX static library lib\clangBasic.lib
[9/26] Building CXX object tools\lld\Common\CMakeFiles\lldCommon.dir\Version.cpp.obj
[10/26] Linking CXX static library lib\lldCommon.lib
[11/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Function.cpp.obj
[12/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Program.cpp.obj
[13/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\ByteCodeEmitter.cpp.obj
[14/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Context.cpp.obj
[15/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\InterpBuiltin.cpp.obj
[16/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Compiler.cpp.obj
[17/26] Building CXX object lib\CodeGen\AsmPrinter\CMakeFiles\LLVMAsmPrinter.dir\AsmPrinter.cpp.obj
[18/26] Linking CXX static library lib\LLVMAsmPrinter.lib
[19/26] Building CXX object lib\LTO\CMakeFiles\LLVMLTO.dir\LTO.cpp.obj
[20/26] Linking CXX static library lib\LLVMLTO.lib
[21/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\EvalEmitter.cpp.obj
[22/26] Linking CXX executable bin\lld.exe
[23/26] Building CXX object tools\clang\lib\AST\CMakeFiles\obj.clangAST.dir\Interp\Disasm.cpp.obj

command timed out: 1200 seconds without output running ['python', '../llvm-zorg/zorg/buildbot/builders/annotated/sanitizer-windows.py', '--jobs=16'], attempting to kill
program finished with exit code 1
elapsedTime=1268.363000

@llvm-ci
Copy link
Collaborator

llvm-ci commented Aug 3, 2024

LLVM Buildbot has detected a new failure on builder clang-aarch64-sve-vls running on linaro-g3-02 while building clang at step 13 "test-suite".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/143/builds/1236

Here is the relevant piece of the build log for the reference:

Step 13 (test-suite) failure: test (failure)
******************** TEST 'test-suite :: Fortran/gfortran/regression/gfortran-regression-execute-regression__random_init_2_f90.test' FAILED ********************

/home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/tools/timeit-target --timeout 7200 --limit-core 0 --limit-cpu 7200 --limit-file-size 209715200 --limit-rss-size 838860800 --redirect-input /dev/null --chdir /home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/Fortran/gfortran/regression/gfortran-regression-execute-regression__random_init_2_f90.wd --summary /home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/Fortran/gfortran/regression/Output/gfortran-regression-execute-regression__random_init_2_f90.test.time /home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/Fortran/gfortran/regression/gfortran-regression-execute-regression__random_init_2_f90

+ /home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/tools/timeit-target --timeout 7200 --limit-core 0 --limit-cpu 7200 --limit-file-size 209715200 --limit-rss-size 838860800 --redirect-input /dev/null --chdir /home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/Fortran/gfortran/regression/gfortran-regression-execute-regression__random_init_2_f90.wd --summary /home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/Fortran/gfortran/regression/Output/gfortran-regression-execute-regression__random_init_2_f90.test.time /home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/Fortran/gfortran/regression/gfortran-regression-execute-regression__random_init_2_f90
/home/tcwg-buildbot/worker/clang-aarch64-sve-vls/test/sandbox/build/tools/timeit-target: error: child terminated by signal 6

********************


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants