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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits