Author: Timm Bäder
Date: 2024-05-07T07:58:42+02:00
New Revision: 05f4448d40f00b9fb2447e1c32cd18a7a9b8b011

URL: 
https://github.com/llvm/llvm-project/commit/05f4448d40f00b9fb2447e1c32cd18a7a9b8b011
DIFF: 
https://github.com/llvm/llvm-project/commit/05f4448d40f00b9fb2447e1c32cd18a7a9b8b011.diff

LOG: [clang][Interp][NFC] Add eval-order test

Demonstrate that this isn't yet working right.

Added: 
    clang/test/AST/Interp/eval-order.cpp

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/clang/test/AST/Interp/eval-order.cpp 
b/clang/test/AST/Interp/eval-order.cpp
new file mode 100644
index 0000000000000..695a43c9d235b
--- /dev/null
+++ b/clang/test/AST/Interp/eval-order.cpp
@@ -0,0 +1,117 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s -fcxx-exceptions 
-triple=x86_64-linux-gnu
+// RUN: %clang_cc1 -std=c++1z -verify %s -fcxx-exceptions 
-triple=x86_64-linux-gnu -fexperimental-new-constant-interpreter
+
+// ref-no-diagnostics
+// expected-no-diagnostics
+
+/// Check that assignment operators evaluate their operands right-to-left.
+/// Copied from test/SemaCXX/constant-expression-cxx1z.cpp
+///
+/// As you can see from the FIXME comments, some of these are not yet working 
correctly
+/// in the new interpreter.
+namespace EvalOrder {
+  template<typename T> struct lvalue {
+    T t;
+    constexpr T &get() { return t; }
+  };
+
+  struct UserDefined {
+    int n = 0;
+    constexpr UserDefined &operator=(const UserDefined&) { return *this; }
+    constexpr UserDefined &operator+=(const UserDefined&) { return *this; }
+    constexpr void operator<<(const UserDefined&) const {}
+    constexpr void operator>>(const UserDefined&) const {}
+    constexpr void operator+(const UserDefined&) const {}
+    constexpr void operator[](int) const {}
+  };
+  constexpr UserDefined ud;
+
+  struct NonMember {};
+  constexpr void operator+=(NonMember, NonMember) {}
+  constexpr void operator<<(NonMember, NonMember) {}
+  constexpr void operator>>(NonMember, NonMember) {}
+  constexpr void operator+(NonMember, NonMember) {}
+  constexpr NonMember nm;
+
+  constexpr void f(...) {}
+
+  // Helper to ensure that 'a' is evaluated before 'b'.
+  struct seq_checker {
+    bool done_a = false;
+    bool done_b = false;
+
+    template <typename T> constexpr T &&a(T &&v) {
+      done_a = true;
+      return (T &&)v;
+    }
+    template <typename T> constexpr T &&b(T &&v) {
+      if (!done_a)
+        throw "wrong";
+      done_b = true;
+      return (T &&)v;
+    }
+
+    constexpr bool ok() { return done_a && done_b; }
+  };
+
+  // SEQ(expr), where part of the expression is tagged A(...) and part is
+  // tagged B(...), checks that A is evaluated before B.
+  #define A sc.a
+  #define B sc.b
+  #define SEQ(...) static_assert([](seq_checker sc) { void(__VA_ARGS__); 
return sc.ok(); }({}))
+
+  // Longstanding sequencing rules.
+  SEQ((A(1), B(2)));
+  SEQ((A(true) ? B(2) : throw "huh?"));
+  SEQ((A(false) ? throw "huh?" : B(2)));
+  SEQ(A(true) && B(true));
+  SEQ(A(false) || B(true));
+
+  // From P0145R3:
+
+  // Rules 1 and 2 have no effect ('b' is not an expression).
+
+  // Rule 3: a->*b
+  // SEQ(A(ud).*B(&UserDefined::n)); FIXME
+  // SEQ(A(&ud)->*B(&UserDefined::n)); FIXME
+
+  // Rule 4: a(b1, b2, b3)
+  // SEQ(A(f)(B(1), B(2), B(3))); FIXME
+
+  // Rule 5: b = a, b @= a
+  // SEQ(B(lvalue<int>().get()) = A(0)); FIXME
+  // SEQ(B(lvalue<UserDefined>().get()) = A(ud)); FIXME
+  SEQ(B(lvalue<int>().get()) += A(0));
+  // SEQ(B(lvalue<UserDefined>().get()) += A(ud)); FIXME
+  // SEQ(B(lvalue<NonMember>().get()) += A(nm)); FIXME
+
+  // Rule 6: a[b]
+  constexpr int arr[3] = {};
+  SEQ(A(arr)[B(0)]);
+  SEQ(A(+arr)[B(0)]);
+  // SEQ(A(0)[B(arr)]); FIXME
+  // SEQ(A(0)[B(+arr)]); FIXME
+  SEQ(A(ud)[B(0)]);
+
+  // Rule 7: a << b
+  SEQ(A(1) << B(2));
+  SEQ(A(ud) << B(ud));
+  SEQ(A(nm) << B(nm));
+
+  // Rule 8: a >> b
+  SEQ(A(1) >> B(2));
+  SEQ(A(ud) >> B(ud));
+  SEQ(A(nm) >> B(nm));
+
+  // No particular order of evaluation is specified in other cases, but we in
+  // practice evaluate left-to-right.
+  // FIXME: Technically we're expected to check for undefined behavior due to
+  // unsequenced read and modification and treat it as non-constant due to UB.
+  SEQ(A(1) + B(2));
+  SEQ(A(ud) + B(ud));
+  SEQ(A(nm) + B(nm));
+  SEQ(f(A(1), B(2)));
+  #undef SEQ
+  #undef A
+  #undef B
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to