Index: clang/lib/AST/Interp/InterpBuiltin.cpp =================================================================== --- clang/lib/AST/Interp/InterpBuiltin.cpp +++ clang/lib/AST/Interp/InterpBuiltin.cpp @@ -84,6 +84,38 @@ return true; } +static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame) { + const Pointer &StrPtr = getParam(Frame, 0); + + if (!CheckArray(S, OpPC, StrPtr)) + return false; + + if (!CheckLive(S, OpPC, StrPtr, AK_Read)) + return false; + + assert(StrPtr.getFieldDesc()->isPrimitiveArray()); + + size_t I = StrPtr.getIndex(); + size_t Len = 0; + for (;;) { + const Pointer &ElemPtr = StrPtr.atIndex(I); + + if (!CheckRange(S, OpPC, ElemPtr, AK_Read)) + return false; + + uint8_t Val = ElemPtr.deref(); + if (Val == 0) + break; + ++I; + ++Len; + } + + // TODO: Push platform-dependent size_t. + S.Stk.push>(Integral<64, false>::from(Len)); + return true; +} + static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F, bool Signaling) { @@ -342,6 +374,10 @@ if (interp__builtin_strcmp(S, OpPC, Frame)) return Ret(S, OpPC, Dummy); break; + case Builtin::BI__builtin_strlen: + if (interp__builtin_strlen(S, OpPC, Frame)) + return Ret(S, OpPC, Dummy); + break; case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: Index: clang/test/AST/Interp/builtin-functions.cpp =================================================================== --- clang/test/AST/Interp/builtin-functions.cpp +++ clang/test/AST/Interp/builtin-functions.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -fexperimental-new-constant-interpreter %s -verify -// RUN: %clang_cc1 -verify=ref %s -Wno-constant-evaluated -// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter %s -verify -// RUN: %clang_cc1 -std=c++20 -verify=ref %s -Wno-constant-evaluated +// RUN: %clang_cc1 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify +// RUN: %clang_cc1 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated +// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify +// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated namespace strcmp { @@ -38,6 +38,70 @@ // ref-note {{dereferenced one-past-the-end}} } +/// Copied from constant-expression-cxx11.cpp +namespace strlen { +constexpr const char *a = "foo\0quux"; + constexpr char b[] = "foo\0quux"; + constexpr int f() { return 'u'; } + constexpr char c[] = { 'f', 'o', 'o', 0, 'q', f(), 'u', 'x', 0 }; + + static_assert(__builtin_strlen("foo") == 3, ""); + static_assert(__builtin_strlen("foo\0quux") == 3, ""); + static_assert(__builtin_strlen("foo\0quux" + 4) == 4, ""); + + constexpr bool check(const char *p) { + return __builtin_strlen(p) == 3 && + __builtin_strlen(p + 1) == 2 && + __builtin_strlen(p + 2) == 1 && + __builtin_strlen(p + 3) == 0 && + __builtin_strlen(p + 4) == 4 && + __builtin_strlen(p + 5) == 3 && + __builtin_strlen(p + 6) == 2 && + __builtin_strlen(p + 7) == 1 && + __builtin_strlen(p + 8) == 0; + } + + static_assert(check(a), ""); + static_assert(check(b), ""); + static_assert(check(c), ""); + + constexpr int over1 = __builtin_strlen(a + 9); // expected-error {{constant expression}} \ + // expected-note {{one-past-the-end}} \ + // expected-note {{in call to}} \ + // ref-error {{constant expression}} \ + // ref-note {{one-past-the-end}} + constexpr int over2 = __builtin_strlen(b + 9); // expected-error {{constant expression}} \ + // expected-note {{one-past-the-end}} \ + // expected-note {{in call to}} \ + // ref-error {{constant expression}} \ + // ref-note {{one-past-the-end}} + constexpr int over3 = __builtin_strlen(c + 9); // expected-error {{constant expression}} \ + // expected-note {{one-past-the-end}} \ + // expected-note {{in call to}} \ + // ref-error {{constant expression}} \ + // ref-note {{one-past-the-end}} + + constexpr int under1 = __builtin_strlen(a - 1); // expected-error {{constant expression}} \ + // expected-note {{cannot refer to element -1}} \ + // ref-error {{constant expression}} \ + // ref-note {{cannot refer to element -1}} + constexpr int under2 = __builtin_strlen(b - 1); // expected-error {{constant expression}} \ + // expected-note {{cannot refer to element -1}} \ + // ref-error {{constant expression}} \ + // ref-note {{cannot refer to element -1}} + constexpr int under3 = __builtin_strlen(c - 1); // expected-error {{constant expression}} \ + // expected-note {{cannot refer to element -1}} \ + // ref-error {{constant expression}} \ + // ref-note {{cannot refer to element -1}} + + constexpr char d[] = { 'f', 'o', 'o' }; // no nul terminator. + constexpr int bad = __builtin_strlen(d); // expected-error {{constant expression}} \ + // expected-note {{one-past-the-end}} \ + // expected-note {{in call to}} \ + // ref-error {{constant expression}} \ + // ref-note {{one-past-the-end}} +} + namespace nan { constexpr double NaN1 = __builtin_nan("");