diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp index f6810fd409019..bbe4e9e6a9243 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerAlignmentChecker.cpp @@ -190,6 +190,20 @@ int getTrailingZerosCount(const MemRegion *R, ProgramStateRef State, return -1; unsigned NaturalAlign = ASTCtx.getTypeAlignInChars(PT).getQuantity(); + if (const FieldRegion *FR = R->getAs()) { + // If this is the first field of a larger struct, we can use the alignment + // of the containing struct try to increase the assumed alignment. + const RegionOffset &Offset = FR->getAsOffset(); + if (!Offset.hasSymbolicOffset() && Offset.getOffset() == 0) { + if (const auto *Base = + FR->getSuperRegion()->getAs()) { + auto BaseTy = Base->getValueType(); + unsigned BaseAlign = ASTCtx.getTypeAlignInChars(BaseTy).getQuantity(); + NaturalAlign = std::max(NaturalAlign, BaseAlign); + } + } + } + if (const ElementRegion *ER = R->getAs()) { int ElTyTZ = APSInt::getUnsigned(NaturalAlign).countTrailingZeros(); diff --git a/clang/test/Analysis/pointer-alignment.c b/clang/test/Analysis/pointer-alignment.c index 9df8dec56b249..4accc82c80a49 100644 --- a/clang/test/Analysis/pointer-alignment.c +++ b/clang/test/Analysis/pointer-alignment.c @@ -202,3 +202,15 @@ void cast_and_assign(void) { // no duplicate assign warn *i = 42; } + +// ---- +struct __attribute__((aligned(8))) AlignedParentStruct { + int a; + int b; +}; + +void write_to_first_member(struct AlignedParentStruct *chunk) { + // No warning because alignment of is inferred from the parent struct. + *(long long*)(&chunk->a) = 0; +} +