rogfer01 created this revision. rogfer01 added reviewers: aaron.ballman, rsmith. rogfer01 added a subscriber: cfe-commits.
This change remove some false positives when taking the address of packed members. - It silences the warning when a cast to uintptr_t/intptr_t happens. - If the field is in a packed record that is overaligned, the field may still be in a suitable offset for the required alignment of the field. We now check this as well. https://reviews.llvm.org/D23657 Files: lib/Sema/SemaChecking.cpp test/Sema/address-packed.c
Index: test/Sema/address-packed.c =================================================================== --- test/Sema/address-packed.c +++ test/Sema/address-packed.c @@ -26,6 +26,7 @@ struct Arguable *get_arguable(); void to_void(void *); +void to_intptr(intptr_t); void g0(void) { { @@ -41,43 +42,48 @@ f1((int *)(void *)&arguable.x); // no-warning to_void(&arguable.x); // no-warning - void *p = &arguable.x; // no-warning; + void *p = &arguable.x; // no-warning to_void(p); + to_intptr((intptr_t)p); // no-warning } { union UnionArguable arguable; f2(&arguable.c); // no-warning f1(&arguable.x); // expected-warning {{packed member 'x' of class or structure 'UnionArguable'}} - f1((int *)(void *)&arguable.x); // no-warning - to_void(&arguable.x); // no-warning + f1((int *)(void *)&arguable.x); // no-warning + to_void(&arguable.x); // no-warning + to_intptr((intptr_t)&arguable.x); // no-warning } { ArguableT arguable; f2(&arguable.c0); // no-warning f1(&arguable.x); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} f2(&arguable.c1); // no-warning - f1((int *)(void *)&arguable.x); // no-warning - to_void(&arguable.x); // no-warning + f1((int *)(void *)&arguable.x); // no-warning + to_void(&arguable.x); // no-warning + to_intptr((intptr_t)&arguable.x); // no-warning } { struct Arguable *arguable = get_arguable(); f2(&arguable->c0); // no-warning f1(&arguable->x); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} f2(&arguable->c1); // no-warning - f1((int *)(void *)&arguable->x); // no-warning - to_void(&arguable->c1); // no-warning + f1((int *)(void *)&arguable->x); // no-warning + to_void(&arguable->c1); // no-warning + to_intptr((intptr_t)&arguable->c1); // no-warning } { ArguableT *arguable = get_arguable(); f2(&(arguable->c0)); // no-warning f1(&(arguable->x)); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} f2(&(arguable->c1)); // no-warning - f1((int *)(void *)&(arguable->x)); // no-warning - to_void(&(arguable->c1)); // no-warning + f1((int *)(void *)&(arguable->x)); // no-warning + to_void(&(arguable->c1)); // no-warning + to_intptr((intptr_t)&(arguable->c1)); // no-warning } } @@ -161,3 +167,18 @@ { return (struct AlignedTo2Bis*)&s->x; // no-warning } + +struct S6 { + int a; + int _; + int c; + char __; + int d; +} __attribute__((packed, aligned(16))) s6; + +void foo() +{ + f1(&s6.a); // no-warning + f1(&s6.c); // no-warning + f1(&s6.d); // expected-warning {{packed member 'd' of class or structure 'S6'}} +} Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -11016,43 +11016,55 @@ } void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { - if (!T->isPointerType()) + if (!T->isPointerType() && !T->isIntegerType()) 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) + (T->isIntegerType() || + (T->isPointerType() && + Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment))) MisalignedMembers.erase(MA); } } } void Sema::RefersToMemberWithReducedAlignment( Expr *E, std::function<void(Expr *, RecordDecl *, ValueDecl *, CharUnits)> Action) { + // return; const auto *ME = dyn_cast<MemberExpr>(E); + CharUnits RequiredAlignment; 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; + auto AlignField = Context.getTypeAlignInChars(MD->getType()); - 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; + RequiredAlignment = std::max(RequiredAlignment, AlignField); + if (RD->hasAttr<PackedAttr>() || MD->hasAttr<PackedAttr>()) { + auto AlignRecord = Context.getTypeAlignInChars(BaseType); + if ((RequiredAlignment > AlignRecord) || + ((Context.toCharUnitsFromBits( + Context.getFieldOffset(cast<FieldDecl>(MD))) % + RequiredAlignment) != 0)) { + // If the struct or the field are packed + // - and the required alignment for the field is larger than the + // alignment of the record, or if not that + // - the offset of the field is misaligned to its required alignment + // then notify that this expression designates a member with reduced + // alignment. + CharUnits Alignment = std::min(AlignField, AlignRecord); + Action(E, RD, MD, Alignment); + break; + } } ME = dyn_cast<MemberExpr>(ME->getBase()); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits