[clang] 2e43ca4 - [clang][Interp] Check variable initialization in Ret op

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 16 03:05:15 PST 2024


Author: Timm Bäder
Date: 2024-02-16T12:05:03+01:00
New Revision: 2e43ca49d06d4cf78a3fd86e1e41175fde083708

URL: https://github.com/llvm/llvm-project/commit/2e43ca49d06d4cf78a3fd86e1e41175fde083708
DIFF: https://github.com/llvm/llvm-project/commit/2e43ca49d06d4cf78a3fd86e1e41175fde083708.diff

LOG: [clang][Interp] Check variable initialization in Ret op

Just like we did with the l-to-r conversion, we need to do this
while the data is still alive.

Added: 
    

Modified: 
    clang/lib/AST/Interp/Context.cpp
    clang/lib/AST/Interp/EvalEmitter.cpp
    clang/lib/AST/Interp/EvalEmitter.h
    clang/lib/AST/Interp/EvaluationResult.cpp
    clang/lib/AST/Interp/EvaluationResult.h
    clang/test/AST/Interp/c.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 6068b1a5680c83..578dc44fe4f8d4 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -88,7 +88,10 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
   assert(Stk.empty());
   ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
 
-  auto Res = C.interpretDecl(VD);
+  bool CheckGlobalInitialized =
+      shouldBeGloballyIndexed(VD) &&
+      (VD->getType()->isRecordType() || VD->getType()->isArrayType());
+  auto Res = C.interpretDecl(VD, CheckGlobalInitialized);
   if (Res.isInvalid()) {
     Stk.clear();
     return false;
@@ -101,25 +104,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
   Stk.clear();
 #endif
 
-  // Ensure global variables are fully initialized.
-  if (shouldBeGloballyIndexed(VD) &&
-      (VD->getType()->isRecordType() || VD->getType()->isArrayType() ||
-       VD->getType()->isAnyComplexType())) {
-    assert(Res.isLValue());
-
-    if (!VD->getType()->isAnyComplexType() &&
-        !Res.checkFullyInitialized(C.getState()))
-      return false;
-
-    // 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;
-    Result = *RValueResult;
-
-  } else
-    Result = Res.toAPValue();
+  Result = Res.toAPValue();
   return true;
 }
 

diff  --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index f14023a23af9b3..6715921ff1d975 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -44,7 +44,9 @@ EvaluationResult EvalEmitter::interpretExpr(const Expr *E,
   return std::move(this->EvalResult);
 }
 
-EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD) {
+EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
+                                            bool CheckFullyInitialized) {
+  this->CheckFullyInitialized = CheckFullyInitialized;
   EvalResult.setSource(VD);
 
   if (!this->visitDecl(VD) && EvalResult.empty())
@@ -131,7 +133,17 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
       return false;
     }
   } else {
-    EvalResult.setPointer(Ptr);
+    if (CheckFullyInitialized) {
+      if (!EvalResult.checkFullyInitialized(S, Ptr))
+        return false;
+
+      std::optional<APValue> RValueResult = Ptr.toRValue(Ctx);
+      if (!RValueResult)
+        return false;
+      EvalResult.setValue(*RValueResult);
+    } else {
+      EvalResult.setValue(Ptr.toAPValue());
+    }
   }
 
   return true;

diff  --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h
index 8159e489f168e3..032c8860ee677a 100644
--- a/clang/lib/AST/Interp/EvalEmitter.h
+++ b/clang/lib/AST/Interp/EvalEmitter.h
@@ -36,7 +36,7 @@ class EvalEmitter : public SourceMapper {
 
   EvaluationResult interpretExpr(const Expr *E,
                                  bool ConvertResultToRValue = false);
-  EvaluationResult interpretDecl(const VarDecl *VD);
+  EvaluationResult interpretDecl(const VarDecl *VD, bool CheckFullyInitialized);
 
   InterpState &getState() { return S; }
 
@@ -89,6 +89,9 @@ class EvalEmitter : public SourceMapper {
   EvaluationResult EvalResult;
   /// Whether the result should be converted to an RValue.
   bool ConvertResultToRValue = false;
+  /// Whether we should check if the result has been fully
+  /// initialized.
+  bool CheckFullyInitialized = false;
 
   /// Temporaries which require storage.
   llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;

diff  --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp
index b44e8f84a1c42d..693ae9ce4a94e6 100644
--- a/clang/lib/AST/Interp/EvaluationResult.cpp
+++ b/clang/lib/AST/Interp/EvaluationResult.cpp
@@ -132,9 +132,10 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
   return Result;
 }
 
-bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
+bool EvaluationResult::checkFullyInitialized(InterpState &S,
+                                             const Pointer &Ptr) const {
   assert(Source);
-  assert(isLValue());
+  assert(empty());
 
   // Our Source must be a VarDecl.
   const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
@@ -143,7 +144,6 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
   assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
   SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
 
-  const Pointer &Ptr = *std::get_if<Pointer>(&Value);
   assert(!Ptr.isZero());
 
   if (const Record *R = Ptr.getRecord())

diff  --git a/clang/lib/AST/Interp/EvaluationResult.h b/clang/lib/AST/Interp/EvaluationResult.h
index 52a6c011e39e1b..28e1ae6ba3e7ab 100644
--- a/clang/lib/AST/Interp/EvaluationResult.h
+++ b/clang/lib/AST/Interp/EvaluationResult.h
@@ -97,7 +97,7 @@ class EvaluationResult final {
   /// LValue and we can't read from it.
   std::optional<APValue> toRValue() const;
 
-  bool checkFullyInitialized(InterpState &S) const;
+  bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;
 
   /// Dump to stderr.
   void dump() const;

diff  --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 31cd2729f0bc72..fe540dc83918fa 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 %s
-// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic-expected,all -std=c11 %s
-// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 %s
-// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic-ref,all -std=c11 %s
+// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=expected,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -pedantic -verify=pedantic-expected,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -verify=ref,all -std=c11 -Wcast-qual %s
+// RUN: %clang_cc1 -triple x86_64-linux -pedantic -verify=pedantic-ref,all -std=c11 -Wcast-qual %s
 
 typedef __INTPTR_TYPE__ intptr_t;
 typedef __PTRDIFF_TYPE__ ptr
diff _t;
@@ -138,3 +138,15 @@ void t14(void) {
                       // pedantic-ref-warning {{array index -1 is before the beginning of the array}}
 
 }
+
+void bar_0(void) {
+  struct C {
+    const int a;
+    int b;
+  };
+
+  const struct C S = {0, 0};
+
+  *(int *)(&S.a) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+  *(int *)(&S.b) = 0; // all-warning {{cast from 'const int *' to 'int *' drops const qualifier}}
+}


        


More information about the cfe-commits mailing list