diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -1010,6 +1010,34 @@ return false; } return true; + } else if (const auto *SL = dyn_cast(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 --- a/clang/test/AST/Interp/literals.cpp +++ b/clang/test/AST/Interp/literals.cpp @@ -350,6 +350,46 @@ #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