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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits