[clang][Interp] Check inc/dec family of ops for initialization
authorTimm Bäder <tbaeder@redhat.com>
Thu, 4 May 2023 13:31:24 +0000 (15:31 +0200)
committerTimm Bäder <tbaeder@redhat.com>
Fri, 16 Jun 2023 13:19:23 +0000 (15:19 +0200)
Differential Revision: https://reviews.llvm.org/D149846

clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Interp.h
clang/test/AST/Interp/literals.cpp

index 3798146b32d1123b08d48d9997e2bf731741c096..8d7f191ebaa097ce59a230279abb03deb1824b2a 100644 (file)
@@ -53,17 +53,6 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
   return true;
 }
 
-static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                             AccessKinds AK) {
-  if (Ptr.isInitialized())
-    return true;
-  if (!S.checkingPotentialConstantExpression()) {
-    const SourceInfo &Loc = S.Current->getSource(OpPC);
-    S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
-  }
-  return false;
-}
-
 static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                         AccessKinds AK) {
   if (Ptr.isActive())
@@ -243,6 +232,18 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
   return false;
 }
 
+bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+                      AccessKinds AK) {
+  if (Ptr.isInitialized())
+    return true;
+
+  if (!S.checkingPotentialConstantExpression()) {
+    const SourceInfo &Loc = S.Current->getSource(OpPC);
+    S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
+  }
+  return false;
+}
+
 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
   if (!CheckLive(S, OpPC, Ptr, AK_Read))
     return false;
index d2f4af82089bf3692e7d6d6aa90521af969e6ef1..dbe8b3889849cd7643184a12ce391720a1838625 100644 (file)
@@ -76,6 +76,9 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
 /// Checks if a value can be loaded from a block.
 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
 
+bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+                      AccessKinds AK);
+
 /// Checks if a value can be stored in a block.
 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
 
@@ -501,9 +504,11 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
 /// 4) Pushes the original (pre-inc) value on the stack.
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool Inc(InterpState &S, CodePtr OpPC) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
+    return false;
+
   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
 }
 
@@ -512,9 +517,11 @@ bool Inc(InterpState &S, CodePtr OpPC) {
 /// 3) Writes the value increased by one back to the pointer
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool IncPop(InterpState &S, CodePtr OpPC) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
+    return false;
+
   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
 }
 
@@ -524,9 +531,11 @@ bool IncPop(InterpState &S, CodePtr OpPC) {
 /// 4) Pushes the original (pre-dec) value on the stack.
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool Dec(InterpState &S, CodePtr OpPC) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
+    return false;
+
   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
 }
 
@@ -535,9 +544,11 @@ bool Dec(InterpState &S, CodePtr OpPC) {
 /// 3) Writes the value decreased by one back to the pointer
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 bool DecPop(InterpState &S, CodePtr OpPC) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
+    return false;
+
   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
 }
 
@@ -562,26 +573,38 @@ bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
 }
 
 inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
+    return false;
+
   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
 }
 
 inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
+    return false;
+
   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
 }
 
 inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
+    return false;
+
   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
 }
 
 inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
-  // FIXME: Check initialization of Ptr
   const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+  if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
+    return false;
+
   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
 }
 
index 5f4c0485ba772996603b67445c1782719996f734..1a93a951ee3f73b26e6db1e1bb9ee136d4c4d089 100644 (file)
@@ -462,14 +462,36 @@ namespace IncDec {
   }
   static_assert(incBool(), "");
 
+  template<typename T, bool Inc>
   constexpr int uninit() {
-    int a;
-    ++a; // ref-note {{increment of uninitialized}} \
-         // FIXME: Should also be rejected by new interpreter
+    T a;
+    if constexpr (Inc)
+      ++a; // ref-note 2{{increment of uninitialized}} \
+           // expected-note 2{{increment of object outside its lifetime}}
+    else
+      --a; // ref-note 2{{decrement of uninitialized}} \
+           // expected-note 2{{decrement of object outside its lifetime}}
     return 1;
   }
-  static_assert(uninit(), ""); // ref-error {{not an integral constant expression}} \
-                               // ref-note {{in call to 'uninit()'}}
+  static_assert(uninit<int, true>(), ""); // ref-error {{not an integral constant expression}} \
+                                          // ref-note {{in call to 'uninit()'}} \
+                                          // expected-error {{not an integral constant expression}} \
+                                          // expected-note {{in call to 'uninit()'}}
+
+  static_assert(uninit<int, false>(), ""); // ref-error {{not an integral constant expression}} \
+                                           // ref-note {{in call to 'uninit()'}} \
+                                           // expected-error {{not an integral constant expression}} \
+                                           // expected-note {{in call to 'uninit()'}}
+
+  static_assert(uninit<float, true>(), ""); // ref-error {{not an integral constant expression}} \
+                                            // ref-note {{in call to 'uninit()'}} \
+                                            // expected-error {{not an integral constant expression}} \
+                                            // expected-note {{in call to 'uninit()'}}
+
+  static_assert(uninit<float, false>(), ""); // ref-error {{not an integral constant expression}} \
+                                             // ref-note {{in call to 'uninit()'}} \
+                                             // expected-error {{not an integral constant expression}} \
+                                             // expected-note {{in call to 'uninit()'}}
 
   constexpr int OverFlow() { // ref-error {{never produces a constant expression}} \
                              // expected-error {{never produces a constant expression}}