================
@@ -1131,63 +1151,98 @@ llvm::Value *CodeGenFunction::emitCountedByPointerSize(
// cmp = (cmp && index > 0)
// return cmp ? result : 0;
- auto GetElementBaseSize = [&](QualType ElementTy) {
- CharUnits ElementSize =
- getContext().getTypeSizeInChars(ElementTy->getPointeeType());
-
- if (ElementSize.isZero()) {
- // This might be a __sized_by (or __counted_by) on a
- // 'void *', which counts bytes, not elements.
- [[maybe_unused]] auto *CAT = ElementTy->getAs<CountAttributedType>();
- assert(CAT && "must have an CountAttributedType");
-
- ElementSize = CharUnits::One();
+ auto GetPointeeSize = [&](QualType PtrTy) -> CharUnits {
+ assert(!PtrTy.isNull());
+ QualType PointeeTy = PtrTy->getPointeeType();
+ assert(!PointeeTy.isNull() &&
+ (PointeeTy->isVoidType() || !PointeeTy->isIncompleteType()) &&
+ "pointee type must have a computable size");
+
+ CharUnits PointeeSize = getContext().getTypeSizeInChars(PointeeTy);
+ if (PointeeSize.isZero()) {
+ // Support GNU extension of treating `void` having size 1.
+ PointeeSize = CharUnits::One();
}
- return std::optional<CharUnits>(ElementSize);
+ return PointeeSize;
};
- // Get the sizes of the original array element and the casted array element,
- // if different.
- std::optional<CharUnits> ArrayElementBaseSize =
- GetElementBaseSize(ArrayBaseFD->getType());
- if (!ArrayElementBaseSize)
- return nullptr;
-
- std::optional<CharUnits> CastedArrayElementBaseSize = ArrayElementBaseSize;
- if (!CastedArrayElementTy.isNull() && CastedArrayElementTy->isPointerType())
{
- CastedArrayElementBaseSize = GetElementBaseSize(CastedArrayElementTy);
- if (!CastedArrayElementBaseSize)
- return nullptr;
- }
-
bool IsSigned = CountFD->getType()->isSignedIntegerType();
+ const auto *CountAttributedTy =
+ ArrayBaseFD->getType()->getAs<CountAttributedType>();
+ assert(CountAttributedTy && "the field's type is not a CountAttributedType");
// count = ptr->count;
- // index = ptr->index;
+ // index = idx;
Value *Count, *Index;
std::tie(Count, Index) = GetCountFieldAndIndex(
*this, ME, ArrayBaseFD, CountFD, Idx, ResType, IsSigned);
if (!Count)
return nullptr;
- // array_element_size = sizeof (*ptr->array)
- auto *ArrayElementSize = llvm::ConstantInt::get(
- ResType, ArrayElementBaseSize->getQuantity(), IsSigned);
-
- // casted_array_element_size = sizeof (*((cast) ptr->array));
- auto *CastedArrayElementSize = llvm::ConstantInt::get(
- ResType, CastedArrayElementBaseSize->getQuantity(), IsSigned);
-
- // array_size = count * array_element_size;
- Value *ArraySize = Builder.CreateMul(Count, ArrayElementSize, "array_size",
- !IsSigned, IsSigned);
+ // For the _or_null variants, a null pointer describes no accessible memory:
+ // count = ptr->array ? count : 0;
+ if (CountAttributedTy->isOrNull()) {
+ assert(EmittedE && "emitBuiltinObjectSize always passes a non-null value");
+ Value *Ptr = nullptr;
+ if (!Idx) {
+ // 1) 'ptr->array'
+ // Reuse the already-emitted pointer value rather than re-loading `ME`.
+ // Re-loading would produce a second, observable access for a volatile
+ // pointer field
+ Ptr = EmittedE;
+ } else {
+ // 2) '&((cast) ptr->array)[idx]'
+ // FIXME: `EmittedE` is the element address, not `ptr->array`, so we fall
+ // back to re-emitting `ME` and the pointer field is loaded twice. This
is
+ // normally harmless accept when the pointer is `volatile`. Avoiding that
----------------
delcypher wrote:
Thanks for spotting that. Fixed.
https://github.com/llvm/llvm-project/pull/213794
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits