diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 5702859996dca..b4e75593dc4a5 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -56,6 +56,41 @@ static bool retInt(InterpState &S, CodePtr OpPC, APValue &Result) { llvm_unreachable("Int isn't 16 or 32 bit?"); } +static void pushSizeT(InterpState &S, uint64_t Val) { + const TargetInfo &TI = S.getCtx().getTargetInfo(); + unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType()); + + switch (SizeTWidth) { + case 64: + S.Stk.push>(Integral<64, false>::from(Val)); + break; + case 32: + S.Stk.push>(Integral<32, false>::from(Val)); + break; + case 16: + S.Stk.push>(Integral<16, false>::from(Val)); + break; + default: + llvm_unreachable("We don't handle this size_t size."); + } +} + +static bool retSizeT(InterpState &S, CodePtr OpPC, APValue &Result) { + const TargetInfo &TI = S.getCtx().getTargetInfo(); + unsigned SizeTWidth = TI.getTypeWidth(TI.getSizeType()); + + switch (SizeTWidth) { + case 64: + return Ret(S, OpPC, Result); + case 32: + return Ret(S, OpPC, Result); + case 16: + return Ret(S, OpPC, Result); + } + + llvm_unreachable("size_t isn't 64 or 32 bit?"); +} + static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, const InterpFrame *Frame) { const Pointer &A = getParam(Frame, 0); @@ -95,6 +130,34 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, 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 Len = 0; + for (size_t I = StrPtr.getIndex();; ++I, ++Len) { + const Pointer &ElemPtr = StrPtr.atIndex(I); + + if (!CheckRange(S, OpPC, ElemPtr, AK_Read)) + return false; + + uint8_t Val = ElemPtr.deref(); + if (Val == 0) + break; + } + + pushSizeT(S, Len); + return true; +} + static bool interp__builtin_nan(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *F, bool Signaling) { @@ -338,6 +401,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, if (interp__builtin_strcmp(S, OpPC, Frame)) return retInt(S, OpPC, Dummy); break; + case Builtin::BI__builtin_strlen: + if (interp__builtin_strlen(S, OpPC, Frame)) + return retSizeT(S, OpPC, Dummy); + break; case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp index 3fd04759e6799..55ebab1122d58 100644 --- a/clang/test/AST/Interp/builtin-functions.cpp +++ b/clang/test/AST/Interp/builtin-functions.cpp @@ -1,9 +1,11 @@ -// 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 -triple avr -std=c++20 -fexperimental-new-constant-interpreter %s -verify -// RUN: %clang_cc1 -triple avr -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 -fexperimental-new-constant-interpreter -triple i686 %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 -fexperimental-new-constant-interpreter -triple i686 %s -verify +// RUN: %clang_cc1 -std=c++20 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated +// RUN: %clang_cc1 -triple avr -std=c++20 -Wno-string-plus-int -fexperimental-new-constant-interpreter %s -verify +// RUN: %clang_cc1 -triple avr -std=c++20 -Wno-string-plus-int -verify=ref %s -Wno-constant-evaluated namespace strcmp { @@ -40,6 +42,70 @@ namespace strcmp { // 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("");