Skip to content

Conversation

tbaederr
Copy link
Contributor

We need to recurse once more here and move the array case into the bigger if chain.

We need to recurse once more here and move the array case into
the bigger if chain.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Mar 19, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 19, 2025

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

Changes

We need to recurse once more here and move the array case into the bigger if chain.


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

3 Files Affected:

  • (modified) clang/lib/AST/ByteCode/Compiler.cpp (+33-31)
  • (modified) clang/lib/AST/ByteCode/Compiler.h (+1-1)
  • (modified) clang/test/AST/ByteCode/cxx20.cpp (+25)
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 3524ab5f86de8..6c846c01fc848 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3650,7 +3650,7 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
 
   assert(V.isStruct());
   assert(V.getStructNumBases() == 0);
-  if (!this->visitAPValueInitializer(V, E))
+  if (!this->visitAPValueInitializer(V, E, E->getType()))
     return false;
 
   return this->emitFinishInit(E);
@@ -4637,48 +4637,27 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
 
 template <class Emitter>
 bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
-                                                const Expr *E) {
-
+                                                const Expr *E, QualType T) {
   if (Val.isStruct()) {
-    const Record *R = this->getRecord(E->getType());
+    const Record *R = this->getRecord(T);
     assert(R);
     for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) {
       const APValue &F = Val.getStructField(I);
       const Record::Field *RF = R->getField(I);
+      QualType FieldType = RF->Decl->getType();
 
-      if (F.isInt() || F.isFloat() || F.isLValue() || F.isMemberPointer()) {
-        PrimType T = classifyPrim(RF->Decl->getType());
-        if (!this->visitAPValue(F, T, E))
-          return false;
-        if (!this->emitInitField(T, RF->Offset, E))
-          return false;
-      } else if (F.isArray()) {
-        assert(RF->Desc->isPrimitiveArray());
-        const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe();
-        PrimType ElemT = classifyPrim(ArrType->getElementType());
-        assert(ArrType);
-
-        if (!this->emitGetPtrField(RF->Offset, E))
+      if (std::optional<PrimType> PT = classify(FieldType)) {
+        if (!this->visitAPValue(F, *PT, E))
           return false;
-
-        for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) {
-          if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E))
-            return false;
-          if (!this->emitInitElem(ElemT, A, E))
-            return false;
-        }
-
-        if (!this->emitPopPtr(E))
+        if (!this->emitInitField(*PT, RF->Offset, E))
           return false;
-      } else if (F.isStruct() || F.isUnion()) {
+      } else {
         if (!this->emitGetPtrField(RF->Offset, E))
           return false;
-        if (!this->visitAPValueInitializer(F, E))
+        if (!this->visitAPValueInitializer(F, E, FieldType))
           return false;
         if (!this->emitPopPtr(E))
           return false;
-      } else {
-        assert(false && "I don't think this should be possible");
       }
     }
     return true;
@@ -4692,6 +4671,28 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
     if (!this->visitAPValue(F, T, E))
       return false;
     return this->emitInitField(T, RF->Offset, E);
+  } else if (Val.isArray()) {
+    const auto *ArrType = T->getAsArrayTypeUnsafe();
+    QualType ElemType = ArrType->getElementType();
+    for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) {
+      const APValue &Elem = Val.getArrayInitializedElt(A);
+      if (std::optional<PrimType> ElemT = classify(ElemType)) {
+        if (!this->visitAPValue(Elem, *ElemT, E))
+          return false;
+        if (!this->emitInitElem(*ElemT, A, E))
+          return false;
+      } else {
+        if (!this->emitConstUint32(A, E))
+          return false;
+        if (!this->emitArrayElemPtrUint32(E))
+          return false;
+        if (!this->visitAPValueInitializer(Elem, E, ElemType))
+          return false;
+        if (!this->emitPopPtr(E))
+          return false;
+      }
+    }
+    return true;
   }
   // TODO: Other types.
 
@@ -6374,7 +6375,8 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
           return false;
         return this->emitInitGlobal(*T, *Index, E);
       }
-      return this->visitAPValueInitializer(TPOD->getValue(), E);
+      return this->visitAPValueInitializer(TPOD->getValue(), E,
+                                           TPOD->getType());
     }
     return false;
   }
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 902da8ffdd330..256e917728886 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -290,7 +290,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
   VarCreationState visitDecl(const VarDecl *VD);
   /// Visit an APValue.
   bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
-  bool visitAPValueInitializer(const APValue &Val, const Expr *E);
+  bool visitAPValueInitializer(const APValue &Val, const Expr *E, QualType T);
   /// Visit the given decl as if we have a reference to it.
   bool visitDeclRef(const ValueDecl *D, const Expr *E);
 
diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp
index 06501de64916a..42e6ae33e92e4 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -964,3 +964,28 @@ namespace PseudoDtor {
   static_assert(f3() == 0);
 #endif
 }
+
+namespace NastyChar {
+  struct nasty_char {
+    template <typename T> friend auto operator<=>(T, T) = delete;
+    template <typename T> friend void operator+(T &&) = delete;
+    template <typename T> friend void operator-(T &&) = delete;
+    template <typename T> friend void operator&(T &&) = delete;
+
+    char c;
+  };
+
+
+  template <unsigned N> struct ToNastyChar {
+    constexpr ToNastyChar(const char (&r)[N]) {
+      for (unsigned I = 0; I != N; ++I)
+        text[I] = nasty_char{r[I]};
+    }
+    nasty_char text[N];
+  };
+
+  template <unsigned N> ToNastyChar(const char (&)[N]) -> ToNastyChar<N>;
+
+  template <ToNastyChar t> constexpr auto to_nasty_char() { return t; }
+  constexpr auto result = to_nasty_char<"12345">();
+}

@tbaederr tbaederr changed the title [clang][bytecode] Fix initialing array struct fields from an APValue [clang][bytecode] Fix initializing array struct fields from an APValue Mar 19, 2025
@tbaederr tbaederr merged commit e0db416 into llvm:main Mar 19, 2025
14 checks passed
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.

2 participants