diff options
Diffstat (limited to 'clang/lib/Sema/SemaChecking.cpp')
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 108 |
1 files changed, 93 insertions, 15 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 6956b0633bc..8d719951912 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -11696,7 +11696,8 @@ void Sema::DiagnoseMisalignedMembers() { } void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { - if (!T->isPointerType()) + E = E->IgnoreParens(); + if (!T->isPointerType() && !T->isIntegerType()) return; if (isa<UnaryOperator>(E) && cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { @@ -11705,7 +11706,9 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(), MisalignedMember(Op)); if (MA != MisalignedMembers.end() && - Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment) + (T->isIntegerType() || + (T->isPointerType() && + Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment))) MisalignedMembers.erase(MA); } } @@ -11713,28 +11716,103 @@ void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { void Sema::RefersToMemberWithReducedAlignment( Expr *E, - std::function<void(Expr *, RecordDecl *, ValueDecl *, CharUnits)> Action) { + std::function<void(Expr *, RecordDecl *, FieldDecl *, CharUnits)> Action) { const auto *ME = dyn_cast<MemberExpr>(E); - while (ME && isa<FieldDecl>(ME->getMemberDecl())) { + if (!ME) + return; + + // For a chain of MemberExpr like "a.b.c.d" this list + // will keep FieldDecl's like [d, c, b]. + SmallVector<FieldDecl *, 4> ReverseMemberChain; + const MemberExpr *TopME = nullptr; + bool AnyIsPacked = false; + do { 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; + auto *FD = dyn_cast<FieldDecl>(MD); + // We do not care about non-data members. + if (!FD || FD->isInvalidDecl()) + return; - 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; + AnyIsPacked = + AnyIsPacked || (RD->hasAttr<PackedAttr>() || MD->hasAttr<PackedAttr>()); + ReverseMemberChain.push_back(FD); + + TopME = ME; + ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParens()); + } while (ME); + assert(TopME && "We did not compute a topmost MemberExpr!"); + + // Not the scope of this diagnostic. + if (!AnyIsPacked) + return; + + const Expr *TopBase = TopME->getBase()->IgnoreParenImpCasts(); + const auto *DRE = dyn_cast<DeclRefExpr>(TopBase); + // TODO: The innermost base of the member expression may be too complicated. + // For now, just disregard these cases. This is left for future + // improvement. + if (!DRE && !isa<CXXThisExpr>(TopBase)) + return; + + // Alignment expected by the whole expression. + CharUnits ExpectedAlignment = Context.getTypeAlignInChars(E->getType()); + + // No need to do anything else with this case. + if (ExpectedAlignment.isOne()) + return; + + // Synthesize offset of the whole access. + CharUnits Offset; + for (auto I = ReverseMemberChain.rbegin(); I != ReverseMemberChain.rend(); + I++) { + Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(*I)); + } + + // Compute the CompleteObjectAlignment as the alignment of the whole chain. + CharUnits CompleteObjectAlignment = Context.getTypeAlignInChars( + ReverseMemberChain.back()->getParent()->getTypeForDecl()); + + // The base expression of the innermost MemberExpr may give + // stronger guarantees than the class containing the member. + if (DRE && !TopME->isArrow()) { + const ValueDecl *VD = DRE->getDecl(); + if (!VD->getType()->isReferenceType()) + CompleteObjectAlignment = + std::max(CompleteObjectAlignment, Context.getDeclAlign(VD)); + } + + // Check if the synthesized offset fulfills the alignment. + if (Offset % ExpectedAlignment != 0 || + // It may fulfill the offset it but the effective alignment may still be + // lower than the expected expression alignment. + CompleteObjectAlignment < ExpectedAlignment) { + // If this happens, we want to determine a sensible culprit of this. + // Intuitively, watching the chain of member expressions from right to + // left, we start with the required alignment (as required by the field + // type) but some packed attribute in that chain has reduced the alignment. + // It may happen that another packed structure increases it again. But if + // we are here such increase has not been enough. So pointing the first + // FieldDecl that either is packed or else its RecordDecl is, + // seems reasonable. + FieldDecl *FD = nullptr; + CharUnits Alignment; + for (FieldDecl *FDI : ReverseMemberChain) { + if (FDI->hasAttr<PackedAttr>() || + FDI->getParent()->hasAttr<PackedAttr>()) { + FD = FDI; + Alignment = std::min( + Context.getTypeAlignInChars(FD->getType()), + Context.getTypeAlignInChars(FD->getParent()->getTypeForDecl())); + break; + } } - ME = dyn_cast<MemberExpr>(ME->getBase()); + assert(FD && "We did not find a packed FieldDecl!"); + Action(E, FD->getParent(), FD, Alignment); } } |