================ @@ -2234,30 +2236,136 @@ static unsigned computePointerOffset(const ASTContext &ASTCtx, return Result; } +/// Does Ptr point to the last subobject? +static bool pointsToLastObject(const Pointer &Ptr) { + Pointer P = Ptr; + while (!P.isRoot()) { + + if (P.isArrayElement()) { + P = P.expand().getArray(); + continue; + } + if (P.isBaseClass()) { + if (P.getRecord()->getNumFields() > 0) + return false; + P = P.getBase(); + continue; + } + + Pointer Base = P.getBase(); + if (const Record *R = Base.getRecord()) { + assert(P.getField()); + if (P.getField()->getFieldIndex() != R->getNumFields() - 1) + return false; + } + P = Base; + } + + return true; +} + +/// Does Ptr point to the last object AND to a flexible array member? +static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr) { + auto isFlexibleArrayMember = [&](const Descriptor *FieldDesc) { + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + FAMKind StrictFlexArraysLevel = + Ctx.getLangOpts().getStrictFlexArraysLevel(); + + if (StrictFlexArraysLevel == FAMKind::Default) + return true; + + unsigned NumElems = FieldDesc->getNumElems(); + if (NumElems == 0 && StrictFlexArraysLevel != FAMKind::IncompleteOnly) + return true; + + if (NumElems == 1 && StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete) + return true; + return false; + }; + + const Descriptor *FieldDesc = Ptr.getFieldDesc(); + if (!FieldDesc->isArray()) + return false; + + return Ptr.isDummy() && pointsToLastObject(Ptr) && + isFlexibleArrayMember(FieldDesc); +} + static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { + const ASTContext &ASTCtx = S.getASTContext(); PrimType KindT = *S.getContext().classify(Call->getArg(1)); - [[maybe_unused]] unsigned Kind = popToAPSInt(S.Stk, KindT).getZExtValue(); - + // From the GCC docs: + // Kind is an integer constant from 0 to 3. If the least significant bit is + // clear, objects are whole variables. If it is set, a closest surrounding + // subobject is considered the object a pointer points to. The second bit + // determines if maximum or minimum of remaining bytes is computed. + unsigned Kind = popToAPSInt(S.Stk, KindT).getZExtValue(); assert(Kind <= 3 && "unexpected kind"); - + bool UseFieldDesc = (Kind & 1u); + bool ReportMinimum = (Kind & 2u); const Pointer &Ptr = S.Stk.pop<Pointer>(); - if (Ptr.isZero()) + if (Call->getArg(0)->HasSideEffects(ASTCtx)) { + // "If there are any side effects in them, it returns (size_t) -1 + // for type 0 or 1 and (size_t) 0 for type 2 or 3." ---------------- shafik wrote:
Maybe instead of calling `Kind` you could call it `Type` b/c you edited the gcc documentation previously but failed to do so here. I think being more consistent w/ the documentation would help in future. https://github.com/llvm/llvm-project/pull/153601 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits