Timm =?utf-8?q?Bäder?= <tbae...@redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/80...@github.com>


https://github.com/tbaederr updated 
https://github.com/llvm/llvm-project/pull/80662

>From b93916c9798ea09488e30b9b0aae9e54ef0b1956 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com>
Date: Thu, 15 Feb 2024 07:03:58 +0100
Subject: [PATCH 1/2] [clang][Interp][NFC] Convert test to verify=expected,both
 style

---
 clang/test/AST/Interp/functions.cpp | 198 ++++++++++------------------
 1 file changed, 68 insertions(+), 130 deletions(-)

diff --git a/clang/test/AST/Interp/functions.cpp 
b/clang/test/AST/Interp/functions.cpp
index 34a832c794c75d..320691336bdd99 100644
--- a/clang/test/AST/Interp/functions.cpp
+++ b/clang/test/AST/Interp/functions.cpp
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
-// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify 
%s
-// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify 
%s
-// RUN: %clang_cc1 -verify=ref %s
-// RUN: %clang_cc1 -std=c++14 -verify=ref %s
-// RUN: %clang_cc1 -std=c++20 -verify=ref %s
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter 
-verify=expected,both %s
+// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter 
-verify=expected,both %s
+// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter 
-verify=expected,both %s
+// RUN: %clang_cc1 -verify=ref,both %s
+// RUN: %clang_cc1 -std=c++14 -verify=ref,both %s
+// RUN: %clang_cc1 -std=c++20 -verify=ref,both %s
 
 constexpr void doNothing() {}
 constexpr int gimme5() {
@@ -23,16 +23,13 @@ static_assert(!identity(false), "");
 
 template<typename A, typename B>
 constexpr bool sameSize() {
-  static_assert(sizeof(A) == sizeof(B), ""); // expected-error {{static 
assertion failed}} \
-                                             // ref-error {{static assertion 
failed}} \
-                                             // expected-note {{evaluates to}} 
\
-                                             // ref-note {{evaluates to}}
+  static_assert(sizeof(A) == sizeof(B), ""); // both-error {{static assertion 
failed}} \
+                                             // both-note {{evaluates to}}
   return true;
 }
 static_assert(sameSize<int, int>(), "");
 static_assert(sameSize<unsigned int, int>(), "");
-static_assert(sameSize<char, long>(), ""); // expected-note {{in instantiation 
of function template specialization}} \
-                                           // ref-note {{in instantiation of 
function template specialization}}
+static_assert(sameSize<char, long>(), ""); // both-note {{in instantiation of 
function template specialization}}
 
 
 constexpr auto add(int a, int b) -> int {
@@ -92,12 +89,9 @@ static_assert(getNum<-2>() == -2, "");
 static_assert(getNum<10>() == 10, "");
 static_assert(getNum() == 5, "");
 
-constexpr int f(); // expected-note {{declared here}} \
-                   // ref-note {{declared here}}
-static_assert(f() == 5, ""); // expected-error {{not an integral constant 
expression}} \
-                             // expected-note {{undefined function 'f'}} \
-                             // ref-error {{not an integral constant 
expression}} \
-                             // ref-note {{undefined function 'f'}}
+constexpr int f(); // both-note {{declared here}}
+static_assert(f() == 5, ""); // both-error {{not an integral constant 
expression}} \
+                             // both-note {{undefined function 'f'}}
 constexpr int a() {
   return f();
 }
@@ -108,17 +102,14 @@ static_assert(a() == 5, "");
 
 constexpr int invalid() {
   // Invalid expression in visit().
-  while(huh) {} // expected-error {{use of undeclared identifier}} \
-                // ref-error {{use of undeclared identifier}}
-
+  while(huh) {} // both-error {{use of undeclared identifier}}
   return 0;
 }
 
 constexpr void invalid2() {
   int i = 0;
   // Invalid expression in discard().
-  huh(); // expected-error {{use of undeclared identifier}} \
-         // ref-error {{use of undeclared identifier}}
+  huh(); // both-error {{use of undeclared identifier}}
 }
 
 namespace FunctionPointers {
@@ -160,8 +151,7 @@ namespace FunctionReturnType {
   constexpr ptr fun() {
       return &fun1;
   }
-  static_assert(fun() == nullptr, ""); // expected-error {{static assertion 
failed}} \
-                                       // ref-error {{static assertion failed}}
+  static_assert(fun() == nullptr, ""); // both-error {{static assertion 
failed}}
 
   constexpr int foo() {
     int (*f)(int *) = fun();
@@ -188,32 +178,23 @@ namespace FunctionReturnType {
   constexpr int (*op2)(int, int) = nullptr;
   static_assert(!op2, "");
 
-  int m() { return 5;} // ref-note {{declared here}} \
-                       // expected-note {{declared here}}
+  int m() { return 5;} // both-note {{declared here}}
   constexpr int (*invalidFnPtr)() = m;
-  static_assert(invalidFnPtr() == 5, ""); // ref-error {{not an integral 
constant expression}} \
-                                 // ref-note {{non-constexpr function 'm'}} \
-                                 // expected-error {{not an integral constant 
expression}} \
-                                 // expected-note {{non-constexpr function 
'm'}}
+  static_assert(invalidFnPtr() == 5, ""); // both-error {{not an integral 
constant expression}} \
+                                          // both-note {{non-constexpr 
function 'm'}}
 }
 
 namespace Comparison {
   void f(), g();
   constexpr void (*pf)() = &f, (*pg)() = &g;
 
-  constexpr bool u13 = pf < pg; // ref-warning {{ordered comparison of 
function pointers}} \
-                                // ref-error {{must be initialized by a 
constant expression}} \
-                                // ref-note {{comparison between '&f' and '&g' 
has unspecified value}} \
-                                // expected-warning {{ordered comparison of 
function pointers}} \
-                                // expected-error {{must be initialized by a 
constant expression}} \
-                                // expected-note {{comparison between '&f' and 
'&g' has unspecified value}}
+  constexpr bool u13 = pf < pg; // both-warning {{ordered comparison of 
function pointers}} \
+                                // both-error {{must be initialized by a 
constant expression}} \
+                                // both-note {{comparison between '&f' and 
'&g' has unspecified value}}
 
-  constexpr bool u14 = pf < (void(*)())nullptr; // ref-warning {{ordered 
comparison of function pointers}} \
-                                                // ref-error {{must be 
initialized by a constant expression}} \
-                                                // ref-note {{comparison 
between '&f' and 'nullptr' has unspecified value}} \
-                                                // expected-warning {{ordered 
comparison of function pointers}} \
-                                                // expected-error {{must be 
initialized by a constant expression}} \
-                                                // expected-note {{comparison 
between '&f' and 'nullptr' has unspecified value}}
+  constexpr bool u14 = pf < (void(*)())nullptr; // both-warning {{ordered 
comparison of function pointers}} \
+                                                // both-error {{must be 
initialized by a constant expression}} \
+                                                // both-note {{comparison 
between '&f' and 'nullptr' has unspecified value}}
 
 
 
@@ -249,31 +230,22 @@ static_assert(doit() == 10, "");
 
 namespace InvalidCall {
   struct S {
-    constexpr int a() const { // expected-error {{never produces a constant 
expression}} \
-                              // ref-error {{never produces a constant 
expression}}
-      return 1 / 0; // expected-note 2{{division by zero}} \
-                    // expected-warning {{is undefined}} \
-                    // ref-note 2{{division by zero}} \
-                    // ref-warning {{is undefined}}
+    constexpr int a() const { // both-error {{never produces a constant 
expression}}
+      return 1 / 0; // both-note 2{{division by zero}} \
+                    // both-warning {{is undefined}}
     }
   };
   constexpr S s;
-  static_assert(s.a() == 1, ""); // expected-error {{not an integral constant 
expression}} \
-                                 // expected-note {{in call to}} \
-                                 // ref-error {{not an integral constant 
expression}} \
-                                 // ref-note {{in call to}}
+  static_assert(s.a() == 1, ""); // both-error {{not an integral constant 
expression}} \
+                                 // both-note {{in call to}}
 
   /// This used to cause an assertion failure in the new constant interpreter.
-  constexpr void func(); // expected-note {{declared here}} \
-                         // ref-note {{declared here}}
+  constexpr void func(); // both-note {{declared here}}
   struct SS {
-    constexpr SS() { func(); } // expected-note {{undefined function }} \
-                               // ref-note {{undefined function}}
+    constexpr SS() { func(); } // both-note {{undefined function }}
   };
-  constexpr SS ss; // expected-error {{must be initialized by a constant 
expression}} \
-                   // expected-note {{in call to 'SS()'}} \
-                   // ref-error {{must be initialized by a constant 
expression}} \
-                   // ref-note {{in call to 'SS()'}}
+  constexpr SS ss; // both-error {{must be initialized by a constant 
expression}} \
+                   // both-note {{in call to 'SS()'}}
 
 
   /// This should not emit a diagnostic.
@@ -299,8 +271,7 @@ namespace CallWithArgs {
 namespace ReturnLocalPtr {
   constexpr int *p() {
     int a = 12;
-    return &a; // ref-warning {{address of stack memory}} \
-               // expected-warning {{address of stack memory}}
+    return &a; // both-warning {{address of stack memory}}
   }
 
   /// GCC rejects the expression below, just like the new interpreter. The 
current interpreter
@@ -313,13 +284,11 @@ namespace ReturnLocalPtr {
   /// new one does not.
   constexpr const int &p2() {
     int a = 12; // ref-note {{declared here}}
-    return a; // ref-warning {{reference to stack memory associated with local 
variable}} \
-              // expected-warning {{reference to stack memory associated with 
local variable}}
+    return a; // both-warning {{reference to stack memory associated with 
local variable}}
   }
 
-  static_assert(p2() == 12, ""); // ref-error {{not an integral constant 
expression}} \
-                                 // ref-note {{read of variable whose lifetime 
has ended}} \
-                                 // expected-error {{not an integral constant 
expression}}
+  static_assert(p2() == 12, ""); // both-error {{not an integral constant 
expression}} \
+                                 // ref-note {{read of variable whose lifetime 
has ended}}
 }
 
 namespace VoidReturn {
@@ -332,22 +301,16 @@ namespace VoidReturn {
 }
 
 namespace InvalidReclRefs {
-  void param(bool b) { // ref-note {{declared here}} \
-                       // expected-note {{declared here}}
-    static_assert(b, ""); // ref-error {{not an integral constant expression}} 
\
-                          // ref-note {{function parameter 'b' with unknown 
value}} \
-                          // expected-error {{not an integral constant 
expression}} \
-                          // expected-note {{function parameter 'b' with 
unknown value}}
+  void param(bool b) { // both-note {{declared here}}
+    static_assert(b, ""); // both-error {{not an integral constant 
expression}} \
+                          // both-note {{function parameter 'b' with unknown 
value}}
     static_assert(true ? true : b, "");
   }
 
 #if __cplusplus >= 202002L
-  consteval void param2(bool b) { // ref-note {{declared here}} \
-                                 // expected-note {{declared here}}
-    static_assert(b, ""); // ref-error {{not an integral constant expression}} 
\
-                          // ref-note {{function parameter 'b' with unknown 
value}} \
-                          // expected-error {{not an integral constant 
expression}} \
-                          // expected-note {{function parameter 'b' with 
unknown value}}
+  consteval void param2(bool b) { // both-note {{declared here}}
+    static_assert(b, ""); // both-error {{not an integral constant 
expression}} \
+                          // both-note {{function parameter 'b' with unknown 
value}}
   }
 #endif
 }
@@ -482,13 +445,10 @@ namespace AddressOf {
   static_assert(&pt->n == &t.n, "");
 
   struct U { int n : 5; } u;
-  int *pbf = __builtin_addressof(u.n); // expected-error {{address of 
bit-field requested}} \
-                                       // ref-error {{address of bit-field 
requested}}
+  int *pbf = __builtin_addressof(u.n); // both-error {{address of bit-field 
requested}}
 
-  S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address 
of a temporary}} \
-                                      // expected-warning {{temporary whose 
address is used as value of local variable 'ptmp' will be destroyed at the end 
of the full-expression}} \
-                                      // ref-error {{taking the address of a 
temporary}} \
-                                      // ref-warning {{temporary whose address 
is used as value of local variable 'ptmp' will be destroyed at the end of the 
full-expression}}
+  S *ptmp = __builtin_addressof(S{}); // both-error {{taking the address of a 
temporary}} \
+                                      // both-warning {{temporary whose 
address is used as value of local variable 'ptmp' will be destroyed at the end 
of the full-expression}}
 
   constexpr int foo() {return 1;}
   static_assert(__builtin_addressof(foo) == foo, "");
@@ -509,8 +469,7 @@ constexpr typename std::remove_reference<T>::type&& move(T 
&&t) noexcept {
 /// The std::move declaration above gets translated to a builtin function.
 namespace Move {
 #if __cplusplus >= 202002L
-  consteval int f_eval() { // expected-note 12{{declared here}} \
-                           // ref-note 12{{declared here}}
+  consteval int f_eval() { // both-note 12{{declared here}}
     return 0;
   }
 
@@ -530,56 +489,35 @@ namespace Move {
     // there is no the copy constructor call when its argument is a prvalue 
because of garanteed copy elision.
     // so we need to test with both prvalue and xvalues.
     { Copy c(C); }
-    { Copy c((Copy(&f_eval))); } // expected-error {{cannot take address of 
consteval}} \
-                                 // ref-error {{cannot take address of 
consteval}}
+    { Copy c((Copy(&f_eval))); } // both-error {{cannot take address of 
consteval}}
     { Copy c(std::move(C)); }
-    { Copy c(std::move(Copy(&f_eval))); } // expected-error {{is not a 
constant expression}} \
-                                          // expected-note {{to a consteval}} \
-                                          // ref-error {{is not a constant 
expression}} \
-                                          // ref-note {{to a consteval}}
-    { Copy c(to_lvalue_ref((Copy(&f_eval)))); } // expected-error {{is not a 
constant expression}} \
-                                                // expected-note {{to a 
consteval}} \
-                                                // ref-error {{is not a 
constant expression}} \
-                                                // ref-note {{to a consteval}}
+    { Copy c(std::move(Copy(&f_eval))); } // both-error {{is not a constant 
expression}} \
+                                          // both-note {{to a consteval}}
+    { Copy c(to_lvalue_ref((Copy(&f_eval)))); } // both-error {{is not a 
constant expression}} \
+                                                // both-note {{to a consteval}}
     { Copy c(to_lvalue_ref(std::move(C))); }
-    { Copy c(to_lvalue_ref(std::move(Copy(&f_eval)))); } // expected-error 
{{is not a constant expression}} \
-                                                         // expected-note {{to 
a consteval}} \
-                                                         // ref-error {{is not 
a constant expression}} \
-                                                         // ref-note {{to a 
consteval}}
+    { Copy c(to_lvalue_ref(std::move(Copy(&f_eval)))); } // both-error {{is 
not a constant expression}} \
+                                                         // both-note {{to a 
consteval}}
     { Copy c = Copy(C); }
-    { Copy c = Copy(Copy(&f_eval)); } // expected-error {{cannot take address 
of consteval}} \
-                                      // ref-error {{cannot take address of 
consteval}}
+    { Copy c = Copy(Copy(&f_eval)); } // both-error {{cannot take address of 
consteval}}
     { Copy c = Copy(std::move(C)); }
-    { Copy c = Copy(std::move(Copy(&f_eval))); } // expected-error {{is not a 
constant expression}} \
-                                                 // expected-note {{to a 
consteval}} \
-                                                 // ref-error {{is not a 
constant expression}} \
-                                                 // ref-note {{to a consteval}}
-    { Copy c = Copy(to_lvalue_ref(Copy(&f_eval))); } // expected-error {{is 
not a constant expression}} \
-                                                     // expected-note {{to a 
consteval}} \
-                                                     // ref-error {{is not a 
constant expression}} \
-                                                     // ref-note {{to a 
consteval}}
+    { Copy c = Copy(std::move(Copy(&f_eval))); } // both-error {{is not a 
constant expression}} \
+                                                 // both-note {{to a 
consteval}}
+    { Copy c = Copy(to_lvalue_ref(Copy(&f_eval))); } // both-error {{is not a 
constant expression}} \
+                                                     // both-note {{to a 
consteval}}
     { Copy c = Copy(to_lvalue_ref(std::move(C))); }
-    { Copy c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); } // 
expected-error {{is not a constant expression}} \
-                                                                // 
expected-note {{to a consteval}} \
-                                                                // ref-error 
{{is not a constant expression}} \
-                                                                // ref-note 
{{to a consteval}}
+    { Copy c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); } // both-error 
{{is not a constant expression}} \
+                                                                // both-note 
{{to a consteval}}
     { Copy c; c = Copy(C); }
-    { Copy c; c = Copy(Copy(&f_eval)); } // expected-error {{cannot take 
address of consteval}} \
-                                         // ref-error {{cannot take address of 
consteval}}
+    { Copy c; c = Copy(Copy(&f_eval)); } // both-error {{cannot take address 
of consteval}}
     { Copy c; c = Copy(std::move(C)); }
-    { Copy c; c = Copy(std::move(Copy(&f_eval))); } // expected-error {{is not 
a constant expression}} \
-                                                    // expected-note {{to a 
consteval}} \
-                                                    // ref-error {{is not a 
constant expression}} \
-                                                    // ref-note {{to a 
consteval}}
-    { Copy c; c = Copy(to_lvalue_ref(Copy(&f_eval))); } // expected-error {{is 
not a constant expression}} \
-                                                        // expected-note {{to 
a consteval}} \
-                                                        // ref-error {{is not 
a constant expression}} \
-                                                        // ref-note {{to a 
consteval}}
+    { Copy c; c = Copy(std::move(Copy(&f_eval))); } // both-error {{is not a 
constant expression}} \
+                                                    // both-note {{to a 
consteval}}
+    { Copy c; c = Copy(to_lvalue_ref(Copy(&f_eval))); } // both-error {{is not 
a constant expression}} \
+                                                        // both-note {{to a 
consteval}}
     { Copy c; c = Copy(to_lvalue_ref(std::move(C))); }
-    { Copy c; c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); } // 
expected-error {{is not a constant expression}} \
-                                                                   // 
expected-note {{to a consteval}} \
-                                                                   // 
ref-error {{is not a constant expression}} \
-                                                                   // ref-note 
{{to a consteval}}
+    { Copy c; c = Copy(to_lvalue_ref(std::move(Copy(&f_eval)))); } // 
both-error {{is not a constant expression}} \
+                                                                   // 
both-note {{to a consteval}}
   }
 #endif
   constexpr int A = std::move(5);

>From aa4ebdd6928cd4e6a8a39a4fd38699037e76fdea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com>
Date: Mon, 5 Feb 2024 10:29:45 +0100
Subject: [PATCH 2/2] [clang][Interp] Do r-to-l conversion immediately when
 returning

First, we need to register local constant variables in C, so we get
the same diagnostic behavior as the current interpeter.

Second, when returning an LValue (as a Pointer), which we eventually
convert to an RValue, we need to do the conversion immediately when
saving the Pointer in the EvaluationResult. Otherwise, we will
possibly deallocate the data before doing the conversion (which will
look at the Block*).
---
 clang/lib/AST/Interp/ByteCodeExprGen.cpp |  3 +--
 clang/lib/AST/Interp/Context.cpp         | 16 ++++------------
 clang/lib/AST/Interp/EvalEmitter.cpp     | 20 ++++++++++++++++++--
 clang/lib/AST/Interp/EvalEmitter.h       |  5 ++++-
 clang/lib/AST/Interp/EvaluationResult.h  |  2 +-
 clang/test/AST/Interp/c.c                | 13 +++++++++++++
 clang/test/Sema/warn-char-subscripts.c   |  1 +
 7 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp 
b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 988765972a36e6..31e7f02dd4305c 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -3243,8 +3243,7 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const 
DeclRefExpr *E) {
   // This happens in C.
   if (!Ctx.getLangOpts().CPlusPlus) {
     if (const auto *VD = dyn_cast<VarDecl>(D);
-        VD && VD->hasGlobalStorage() && VD->getAnyInitializer() &&
-        VD->getType().isConstQualified()) {
+        VD && VD->getAnyInitializer() && VD->getType().isConstQualified()) {
       if (!this->visitVarDecl(VD))
         return false;
       // Retry.
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 7396db22943663..6068b1a5680c83 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -44,7 +44,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, 
APValue &Result) {
   assert(Stk.empty());
   ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
 
-  auto Res = C.interpretExpr(E);
+  auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());
 
   if (Res.isInvalid()) {
     Stk.clear();
@@ -58,16 +58,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, 
APValue &Result) {
   Stk.clear();
 #endif
 
-  // Implicit lvalue-to-rvalue conversion.
-  if (E->isGLValue()) {
-    std::optional<APValue> RValueResult = Res.toRValue();
-    if (!RValueResult) {
-      return false;
-    }
-    Result = *RValueResult;
-  } else {
-    Result = Res.toAPValue();
-  }
+  Result = Res.toAPValue();
 
   return true;
 }
@@ -120,7 +111,8 @@ bool Context::evaluateAsInitializer(State &Parent, const 
VarDecl *VD,
         !Res.checkFullyInitialized(C.getState()))
       return false;
 
-    // lvalue-to-rvalue conversion.
+    // lvalue-to-rvalue conversion. We do this manually here so we can
+    // examine the result above before converting and returning it.
     std::optional<APValue> RValueResult = Res.toRValue();
     if (!RValueResult)
       return false;
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp 
b/clang/lib/AST/Interp/EvalEmitter.cpp
index c1e4ce3ebb0729..f14023a23af9b3 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -33,7 +33,9 @@ EvalEmitter::~EvalEmitter() {
   }
 }
 
-EvaluationResult EvalEmitter::interpretExpr(const Expr *E) {
+EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
+                                            bool ConvertResultToRValue) {
+  this->ConvertResultToRValue = ConvertResultToRValue;
   EvalResult.setSource(E);
 
   if (!this->visitExpr(E) && EvalResult.empty())
@@ -119,12 +121,26 @@ template <PrimType OpType> bool 
EvalEmitter::emitRet(const SourceInfo &Info) {
 template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
   if (!isActive())
     return true;
-  EvalResult.setPointer(S.Stk.pop<Pointer>());
+
+  const Pointer &Ptr = S.Stk.pop<Pointer>();
+  // Implicitly convert lvalue to rvalue, if requested.
+  if (ConvertResultToRValue) {
+    if (std::optional<APValue> V = Ptr.toRValue(Ctx)) {
+      EvalResult.setValue(*V);
+    } else {
+      return false;
+    }
+  } else {
+    EvalResult.setPointer(Ptr);
+  }
+
   return true;
 }
 template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
   if (!isActive())
     return true;
+  // Function pointers cannot be converted to rvalues.
+  assert(!ConvertResultToRValue);
   EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
   return true;
 }
diff --git a/clang/lib/AST/Interp/EvalEmitter.h 
b/clang/lib/AST/Interp/EvalEmitter.h
index deb2ebc4e61fa0..8159e489f168e3 100644
--- a/clang/lib/AST/Interp/EvalEmitter.h
+++ b/clang/lib/AST/Interp/EvalEmitter.h
@@ -34,7 +34,8 @@ class EvalEmitter : public SourceMapper {
   using AddrTy = uintptr_t;
   using Local = Scope::Local;
 
-  EvaluationResult interpretExpr(const Expr *E);
+  EvaluationResult interpretExpr(const Expr *E,
+                                 bool ConvertResultToRValue = false);
   EvaluationResult interpretDecl(const VarDecl *VD);
 
   InterpState &getState() { return S; }
@@ -86,6 +87,8 @@ class EvalEmitter : public SourceMapper {
   InterpState S;
   /// Location to write the result to.
   EvaluationResult EvalResult;
+  /// Whether the result should be converted to an RValue.
+  bool ConvertResultToRValue = false;
 
   /// Temporaries which require storage.
   llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
diff --git a/clang/lib/AST/Interp/EvaluationResult.h 
b/clang/lib/AST/Interp/EvaluationResult.h
index 2b9fc16f1a0abc..52a6c011e39e1b 100644
--- a/clang/lib/AST/Interp/EvaluationResult.h
+++ b/clang/lib/AST/Interp/EvaluationResult.h
@@ -56,8 +56,8 @@ class EvaluationResult final {
   void setSource(DeclTy D) { Source = D; }
 
   void setValue(const APValue &V) {
+    // V could still be an LValue.
     assert(empty());
-    assert(!V.isLValue());
     Value = std::move(V);
     Kind = RValue;
   }
diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 85c195d33a96d7..31cd2729f0bc72 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -125,3 +125,16 @@ struct XY { int before; struct XX xx, *xp; float* after; } 
xy[] = {
   0,              // all-warning {{initializer overrides prior initialization 
of this subobject}}
   &xy[2].xx.a, &xy[2].xx, &global_float
 };
+
+void t14(void) {
+  int array[256] = { 0 }; // expected-note {{array 'array' declared here}} \
+                          // pedantic-expected-note {{array 'array' declared 
here}} \
+                          // ref-note {{array 'array' declared here}} \
+                          // pedantic-ref-note {{array 'array' declared here}}
+  const char b = -1;
+  int val = array[b]; // expected-warning {{array index -1 is before the 
beginning of the array}} \
+                      // pedantic-expected-warning {{array index -1 is before 
the beginning of the array}} \
+                      // ref-warning {{array index -1 is before the beginning 
of the array}} \
+                      // pedantic-ref-warning {{array index -1 is before the 
beginning of the array}}
+
+}
diff --git a/clang/test/Sema/warn-char-subscripts.c 
b/clang/test/Sema/warn-char-subscripts.c
index 0a012f68feae07..c2f7a3731d72c8 100644
--- a/clang/test/Sema/warn-char-subscripts.c
+++ b/clang/test/Sema/warn-char-subscripts.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -Wchar-subscripts -fsyntax-only -verify %s
+// RUN: %clang_cc1 -Wchar-subscripts -fsyntax-only -verify %s 
-fexperimental-new-constant-interpreter
 
 void t1(void) {
   int array[1] = { 0 };

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

Reply via email to