[clang] 0a3243d - [clang][Interp] Array initialization via string literal

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 25 05:24:02 PST 2023


Author: Timm Bäder
Date: 2023-01-25T14:22:05+01:00
New Revision: 0a3243de62c1f0a1e0c2b3c5b4aae8323bef9605

URL: https://github.com/llvm/llvm-project/commit/0a3243de62c1f0a1e0c2b3c5b4aae8323bef9605
DIFF: https://github.com/llvm/llvm-project/commit/0a3243de62c1f0a1e0c2b3c5b4aae8323bef9605.diff

LOG: [clang][Interp] Array initialization via string literal

Differential Revision: https://reviews.llvm.org/D137488

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/test/AST/Interp/literals.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 2581c1c36da2..ae8bf377d262 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1010,6 +1010,34 @@ bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
         return false;
     }
     return true;
+  } else if (const auto *SL = dyn_cast<StringLiteral>(Initializer)) {
+    const ConstantArrayType *CAT =
+        Ctx.getASTContext().getAsConstantArrayType(SL->getType());
+    assert(CAT && "a string literal that's not a constant array?");
+
+    // If the initializer string is too long, a diagnostic has already been
+    // emitted. Read only the array length from the string literal.
+    unsigned N =
+        std::min(unsigned(CAT->getSize().getZExtValue()), SL->getLength());
+    size_t CharWidth = SL->getCharByteWidth();
+
+    for (unsigned I = 0; I != N; ++I) {
+      uint32_t CodeUnit = SL->getCodeUnit(I);
+
+      if (CharWidth == 1) {
+        this->emitConstSint8(CodeUnit, SL);
+        this->emitInitElemSint8(I, SL);
+      } else if (CharWidth == 2) {
+        this->emitConstUint16(CodeUnit, SL);
+        this->emitInitElemUint16(I, SL);
+      } else if (CharWidth == 4) {
+        this->emitConstUint32(CodeUnit, SL);
+        this->emitInitElemUint32(I, SL);
+      } else {
+        llvm_unreachable("unsupported character width");
+      }
+    }
+    return true;
   }
 
   assert(false && "Unknown expression for array initialization");

diff  --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 4c88e861a443..4ba6d750db78 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -350,6 +350,46 @@ namespace strings {
 #endif
 
 #pragma clang diagnostic pop
+
+  constexpr char foo[12] = "abc";
+  static_assert(foo[0] == 'a', "");
+  static_assert(foo[1] == 'b', "");
+  static_assert(foo[2] == 'c', "");
+  static_assert(foo[3] == 0, "");
+  static_assert(foo[11] == 0, "");
+
+  constexpr char foo2[] = "abc\0def";
+  static_assert(foo2[0] == 'a', "");
+  static_assert(foo2[3] == '\0', "");
+  static_assert(foo2[6] == 'f', "");
+  static_assert(foo2[7] == '\0', "");
+  static_assert(foo2[8] == '\0', ""); // expected-error {{not an integral constant expression}} \
+                                      // expected-note {{read of dereferenced one-past-the-end pointer}} \
+                                      // ref-error {{not an integral constant expression}} \
+                                      // ref-note {{read of dereferenced one-past-the-end pointer}}
+
+  constexpr char foo3[4] = "abc";
+  static_assert(foo3[3] == '\0', "");
+  static_assert(foo3[4] == '\0', ""); // expected-error {{not an integral constant expression}} \
+                                      // expected-note {{read of dereferenced one-past-the-end pointer}} \
+                                      // ref-error {{not an integral constant expression}} \
+                                      // ref-note {{read of dereferenced one-past-the-end pointer}}
+
+  constexpr char foo4[2] = "abcd"; // expected-error {{initializer-string for char array is too long}} \
+                                   // ref-error {{initializer-string for char array is too long}}
+  static_assert(foo4[0] == 'a', "");
+  static_assert(foo4[1] == 'b', "");
+  static_assert(foo4[2] == '\0', ""); // expected-error {{not an integral constant expression}} \
+                                      // expected-note {{read of dereferenced one-past-the-end pointer}} \
+                                      // ref-error {{not an integral constant expression}} \
+                                      // ref-note {{read of dereferenced one-past-the-end pointer}}
+
+constexpr char foo5[12] = "abc\xff";
+#if defined(__CHAR_UNSIGNED__) || __CHAR_BIT__ > 8
+static_assert(foo5[3] == 255, "");
+#else
+static_assert(foo5[3] == -1, "");
+#endif
 };
 
 #if __cplusplus > 201402L


        


More information about the cfe-commits mailing list