diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index ec01b04fcf9..ff18e094bda 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8302,6 +8302,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, DiagnoseNullConversion(S, E, T, CC); + S.DiscardMisalignedMemberAddress(Target, E); + if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -9371,6 +9373,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) CheckForIntOverflow(E); + DiagnoseMisalignedMembers(); } void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, @@ -10916,3 +10919,67 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } + +void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment) { + MisalignedMembers.emplace_back(E, RD, MD, Alignment); +} + +void Sema::DiagnoseMisalignedMembers() { + for (MisalignedMember &m : MisalignedMembers) { + Diag(m.E->getLocStart(), diag::warn_taking_address_of_packed_member) + << m.MD << m.RD << m.E->getSourceRange(); + } + MisalignedMembers.clear(); +} + +void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { + if (!T->isPointerType()) + return; + if (isa<UnaryOperator>(E) && + cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { + auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); + if (isa<MemberExpr>(Op)) { + auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(), + MisalignedMember(Op)); + if (MA != MisalignedMembers.end() && + Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment) + MisalignedMembers.erase(MA); + } + } +} + +void Sema::RefersToMemberWithReducedAlignment( + Expr *E, + std::function<void(Expr *, RecordDecl *, ValueDecl *, CharUnits)> Action) { + const auto *ME = dyn_cast<MemberExpr>(E); + while (ME && isa<FieldDecl>(ME->getMemberDecl())) { + QualType BaseType = ME->getBase()->getType(); + if (ME->isArrow()) + BaseType = BaseType->getPointeeType(); + RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl(); + + ValueDecl *MD = ME->getMemberDecl(); + bool ByteAligned = Context.getTypeAlignInChars(MD->getType()).isOne(); + if (ByteAligned) // Attribute packed does not have any effect. + break; + + if (!ByteAligned && + (RD->hasAttr<PackedAttr>() || (MD->hasAttr<PackedAttr>()))) { + CharUnits Alignment = std::min(Context.getTypeAlignInChars(MD->getType()), + Context.getTypeAlignInChars(BaseType)); + // Notify that this expression designates a member with reduced alignment + Action(E, RD, MD, Alignment); + break; + } + ME = dyn_cast<MemberExpr>(ME->getBase()); + } +} + +void Sema::CheckAddressOfPackedMember(Expr *rhs) { + using namespace std::placeholders; + RefersToMemberWithReducedAlignment( + rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, + _2, _3, _4)); +} + |