[clang] [clang][bytecode] Implement __builtin_{memchr,strchr,char_memchr} (PR #130420)

Nikolas Klauser via cfe-commits cfe-commits at lists.llvm.org
Sun Mar 9 04:20:49 PDT 2025


================
@@ -1960,13 +1960,103 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
 
   // However, if we read all the available bytes but were instructed to read
   // even more, diagnose this as a "read of dereferenced one-past-the-end
-  // pointer". This is what would happen if we called CheckRead() on every array
+  // pointer". This is what would happen if we called CheckLoad() on every array
   // element.
   S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_past_end)
       << AK_Read << S.Current->getRange(OpPC);
   return false;
 }
 
+static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC,
+                                   const InterpFrame *Frame,
+                                   const Function *Func, const CallExpr *Call) {
+  unsigned ID = Func->getBuiltinID();
+  if (ID == Builtin::BImemchr || ID == Builtin::BIwcschr ||
+      ID == Builtin::BIstrchr || ID == Builtin::BIwmemchr)
+    diagnoseNonConstexprBuiltin(S, OpPC, ID);
+
+  const Pointer &Ptr = getParam<Pointer>(Frame, 0);
+  APSInt Desired;
+  std::optional<APSInt> MaxLength;
+  if (Call->getNumArgs() == 3) {
+    MaxLength =
+        peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)), 0);
+    Desired = peekToAPSInt(
+        S.Stk, *S.getContext().classify(Call->getArg(1)),
+        align(primSize(*S.getContext().classify(Call->getArg(2)))) +
+            align(primSize(*S.getContext().classify(Call->getArg(1)))));
+  } else {
+    Desired = peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(1)));
+  }
+
+  if (MaxLength && MaxLength->isZero()) {
+    S.Stk.push<Pointer>();
+    return true;
+  }
+
+  if (Ptr.isDummy())
+    return false;
+
+  // Null is only okay if the given size is 0.
+  if (Ptr.isZero()) {
+    S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_null)
+        << AK_Read;
+    return false;
+  }
+
+  QualType ElemTy = Ptr.getFieldDesc()->isArray()
+                        ? Ptr.getFieldDesc()->getElemQualType()
+                        : Ptr.getFieldDesc()->getType();
+  bool IsRawByte = ID == Builtin::BImemchr || ID == Builtin::BI__builtin_memchr;
+
+  // Give up on byte-oriented matching against multibyte elements.
+  if (IsRawByte && !isOneByteCharacterType(ElemTy)) {
+    S.FFDiag(S.Current->getSource(OpPC),
+             diag::note_constexpr_memchr_unsupported)
+        << S.getASTContext().BuiltinInfo.getQuotedName(ID) << ElemTy;
+    return false;
+  }
+
+  if (ID == Builtin::BIstrchr || ID == Builtin::BI__builtin_strchr) {
+    // strchr compares directly to the passed integer, and therefore
+    // always fails if given an int that is not a char.
+    if (Desired !=
+        Desired.trunc(S.getASTContext().getCharWidth()).getSExtValue()) {
----------------
philnik777 wrote:

Are you sure about this? cppreference seems to disagree with you: https://en.cppreference.com/w/cpp/string/byte/strchr

https://github.com/llvm/llvm-project/pull/130420


More information about the cfe-commits mailing list