/// actually abstract.
bool mayBeAbstract() const;
+ /// Determine whether it's impossible for a class to be derived from this
+ /// class. This is best-effort, and may conservatively return false.
+ bool isEffectivelyFinal() const;
+
/// If this is the closure type of a lambda expression, retrieve the
/// number to be used for name mangling in the Itanium C++ ABI.
///
return false;
}
+bool CXXRecordDecl::isEffectivelyFinal() const {
+ auto *Def = getDefinition();
+ if (!Def)
+ return false;
+ if (Def->hasAttr<FinalAttr>())
+ return true;
+ if (const auto *Dtor = Def->getDestructor())
+ if (Dtor->hasAttr<FinalAttr>())
+ return true;
+ return false;
+}
+
void CXXDeductionGuideDecl::anchor() {}
bool ExplicitSpecifier::isEquivalent(const ExplicitSpecifier Other) const {
// Similarly, if the class itself or its destructor is marked 'final',
// the class can't be derived from and we can therefore devirtualize the
// member function call.
- if (BestDynamicDecl->hasAttr<FinalAttr>())
+ if (BestDynamicDecl->isEffectivelyFinal())
return DevirtualizedMethod;
- if (const auto *dtor = BestDynamicDecl->getDestructor()) {
- if (dtor->hasAttr<FinalAttr>())
- return DevirtualizedMethod;
- }
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
if (const auto *RefTy = RetTy->getAs<ReferenceType>()) {
QualType PTy = RefTy->getPointeeType();
if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
- RetAttrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
- .getQuantity());
+ RetAttrs.addDereferenceableAttr(
+ getMinimumObjectSize(PTy).getQuantity());
else if (getContext().getTargetAddressSpace(PTy) == 0 &&
!CodeGenOpts.NullPointerIsValid)
RetAttrs.addAttribute(llvm::Attribute::NonNull);
if (const auto *RefTy = ParamType->getAs<ReferenceType>()) {
QualType PTy = RefTy->getPointeeType();
if (!PTy->isIncompleteType() && PTy->isConstantSizeType())
- Attrs.addDereferenceableAttr(getContext().getTypeSizeInChars(PTy)
- .getQuantity());
+ Attrs.addDereferenceableAttr(
+ getMinimumObjectSize(PTy).getQuantity());
else if (getContext().getTargetAddressSpace(PTy) == 0 &&
!CodeGenOpts.NullPointerIsValid)
Attrs.addAttribute(llvm::Attribute::NonNull);
/// Return the best known alignment for an unknown pointer to a
/// particular class.
CharUnits CodeGenModule::getClassPointerAlignment(const CXXRecordDecl *RD) {
- if (!RD->isCompleteDefinition())
+ if (!RD->hasDefinition())
return CharUnits::One(); // Hopefully won't be used anywhere.
auto &layout = getContext().getASTRecordLayout(RD);
// If the class is final, then we know that the pointer points to an
// object of that type and can use the full alignment.
- if (RD->hasAttr<FinalAttr>()) {
+ if (RD->isEffectivelyFinal())
return layout.getAlignment();
// Otherwise, we have to assume it could be a subclass.
- } else {
- return layout.getNonVirtualAlignment();
- }
+ return layout.getNonVirtualAlignment();
+}
+
+/// Return the smallest possible amount of storage that might be allocated
+/// starting from the beginning of an object of a particular class.
+///
+/// This may be smaller than sizeof(RD) if RD has virtual base classes.
+CharUnits CodeGenModule::getMinimumClassObjectSize(const CXXRecordDecl *RD) {
+ if (!RD->hasDefinition())
+ return CharUnits::One();
+
+ auto &layout = getContext().getASTRecordLayout(RD);
+
+ // If the class is final, then we know that the pointer points to an
+ // object of that type and can use the full alignment.
+ if (RD->isEffectivelyFinal())
+ return layout.getSize();
+
+ // Otherwise, we have to assume it could be a subclass.
+ return std::max(layout.getNonVirtualSize(), CharUnits::One());
}
/// Return the best known alignment for a pointer to a virtual base,
if (SanOpts.has(SanitizerKind::ObjectSize) &&
!SkippedChecks.has(SanitizerKind::ObjectSize) &&
!Ty->isIncompleteType()) {
- uint64_t TySize = getContext().getTypeSizeInChars(Ty).getQuantity();
+ uint64_t TySize = CGM.getMinimumObjectSize(Ty).getQuantity();
llvm::Value *Size = llvm::ConstantInt::get(IntPtrTy, TySize);
if (ArraySize)
Size = Builder.CreateMul(Size, ArraySize);
!SkippedChecks.has(SanitizerKind::Alignment)) {
AlignVal = Alignment.getQuantity();
if (!Ty->isIncompleteType() && !AlignVal)
- AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
+ AlignVal =
+ getNaturalTypeAlignment(Ty, nullptr, nullptr, /*ForPointeeType=*/true)
+ .getQuantity();
// The glvalue must be suitably aligned.
if (AlignVal > 1 &&
/// Returns the assumed alignment of an opaque pointer to the given class.
CharUnits getClassPointerAlignment(const CXXRecordDecl *CD);
+ /// Returns the minimum object size for an object of the given class type
+ /// (or a class derived from it).
+ CharUnits getMinimumClassObjectSize(const CXXRecordDecl *CD);
+
+ /// Returns the minimum object size for an object of the given type.
+ CharUnits getMinimumObjectSize(QualType Ty) {
+ if (CXXRecordDecl *RD = Ty->getAsCXXRecordDecl())
+ return getMinimumClassObjectSize(RD);
+ return getContext().getTypeSizeInChars(Ty);
+ }
+
/// Returns the assumed alignment of a virtual base of a class.
CharUnits getVBaseAlignment(CharUnits DerivedAlign,
const CXXRecordDecl *Derived,
p(42);
}
+namespace VBaseObjectSize {
+ // Note: C is laid out such that offsetof(C, B) + sizeof(B) extends outside
+ // the C object.
+ struct alignas(16) A { void *a1, *a2; };
+ struct B : virtual A { void *b; };
+ struct C : virtual A, virtual B {};
+ // CHECK-LABEL: define {{.*}} @_ZN15VBaseObjectSize1fERNS_1BE(
+ B &f(B &b) {
+ // Size check: check for nvsize(B) == 16 (do not require size(B) == 32)
+ // CHECK: [[SIZE:%.+]] = call i{{32|64}} @llvm.objectsize.i64.p0i8(
+ // CHECK: icmp uge i{{32|64}} [[SIZE]], 16,
+
+ // Alignment check: check for nvalign(B) == 8 (do not require align(B) == 16)
+ // CHECK: [[PTRTOINT:%.+]] = ptrtoint {{.*}} to i64,
+ // CHECK: and i64 [[PTRTOINT]], 7,
+ return b;
+ }
+}
+
namespace FunctionSanitizerVirtualCalls {
struct A {
virtual void f() {}
// CHECK: getelementptr inbounds i8, i8* {{.*}}, i64 8
// CHECK: ret %"struct.Test13::D"*
- // WIN64-LABEL: define weak_odr dso_local dereferenceable(32) %"struct.Test13::D"* @"?foo1@D@Test13@@$4PPPPPPPE@A@EAAAEAUB1@2@XZ"(
+ // WIN64-LABEL: define weak_odr dso_local dereferenceable(8) %"struct.Test13::D"* @"?foo1@D@Test13@@$4PPPPPPPE@A@EAAAEAUB1@2@XZ"(
// This adjustment.
// WIN64: getelementptr inbounds i8, i8* {{.*}}, i64 -12
// Call implementation.