Why did we upgrade the unaligned reference binding from a warning to an error? That will make it hard to roll this change out across many codebases.
On Thu, Jul 14, 2016 at 7:10 AM, Roger Ferrer Ibanez via cfe-commits < cfe-commits@lists.llvm.org> wrote: > Author: rogfer01 > Date: Thu Jul 14 09:10:43 2016 > New Revision: 275417 > > URL: http://llvm.org/viewvc/llvm-project?rev=275417&view=rev > Log: > Diagnose taking address and reference binding of packed members > > This patch implements PR#22821. > > Taking the address of a packed member is dangerous since the reduced > alignment of the pointee is lost. This can lead to memory alignment > faults in some architectures if the pointer value is dereferenced. > > This change adds a new warning to clang emitted when taking the address > of a packed member. A packed member is either a field/data member > declared as attribute((packed)) or belonging to a struct/class > declared as such. The associated flag is -Waddress-of-packed-member. > Conversions (either implicit or via a valid casting) to pointer types > with lower or equal alignment requirements (e.g. void* or char*) > silence the warning. > > This change also adds a new error diagnostic when the user attempts to > bind a reference to a packed member, regardless of the alignment. > > Differential Revision: https://reviews.llvm.org/D20561 > > > > Added: > cfe/trunk/test/Sema/address-packed-member-memops.c > cfe/trunk/test/Sema/address-packed.c > cfe/trunk/test/SemaCXX/address-packed-member-memops.cpp > cfe/trunk/test/SemaCXX/address-packed.cpp > Modified: > cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > cfe/trunk/include/clang/Sema/Sema.h > cfe/trunk/lib/Sema/SemaCast.cpp > cfe/trunk/lib/Sema/SemaChecking.cpp > cfe/trunk/lib/Sema/SemaExpr.cpp > cfe/trunk/lib/Sema/SemaInit.cpp > > Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=275417&r1=275416&r2=275417&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) > +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 14 > 09:10:43 2016 > @@ -5425,6 +5425,11 @@ def warn_pointer_indirection_from_incomp > "dereference of type %1 that was reinterpret_cast from type %0 has > undefined " > "behavior">, > InGroup<UndefinedReinterpretCast>, DefaultIgnore; > +def warn_taking_address_of_packed_member : Warning< > + "taking address of packed member %0 of class or structure %q1 may > result in an unaligned pointer value">, > + InGroup<DiagGroup<"address-of-packed-member">>; > +def err_binding_reference_to_packed_member : Error< > + "binding reference to packed member %0 of class or structure %q1">; > > def err_objc_object_assignment : Error< > "cannot assign to class object (%0 invalid)">; > > Modified: cfe/trunk/include/clang/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=275417&r1=275416&r2=275417&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Sema/Sema.h (original) > +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jul 14 09:10:43 2016 > @@ -9518,6 +9518,10 @@ private: > void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, > const Expr * const *ExprArgs); > > + /// \brief Check if we are taking the address of a packed field > + /// as this may be a problem if the pointer value is dereferenced. > + void CheckAddressOfPackedMember(Expr *rhs); > + > /// \brief The parser's current scope. > /// > /// The parser maintains this state here. > @@ -9596,6 +9600,51 @@ public: > // Emitting members of dllexported classes is delayed until the class > // (including field initializers) is fully parsed. > SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses; > + > +private: > + /// \brief Helper class that collects misaligned member designations and > + /// their location info for delayed diagnostics. > + struct MisalignedMember { > + Expr *E; > + RecordDecl *RD; > + ValueDecl *MD; > + CharUnits Alignment; > + > + MisalignedMember() : E(), RD(), MD(), Alignment() {} > + MisalignedMember(Expr *E, RecordDecl *RD, ValueDecl *MD, > + CharUnits Alignment) > + : E(E), RD(RD), MD(MD), Alignment(Alignment) {} > + explicit MisalignedMember(Expr *E) > + : MisalignedMember(E, nullptr, nullptr, CharUnits()) {} > + > + bool operator==(const MisalignedMember &m) { return this->E == m.E; } > + }; > + /// \brief Small set of gathered accesses to potentially misaligned > members > + /// due to the packed attribute. > + SmallVector<MisalignedMember, 4> MisalignedMembers; > + > + /// \brief Adds an expression to the set of gathered misaligned members. > + void AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl > *MD, > + CharUnits Alignment); > + > +public: > + /// \brief Diagnoses the current set of gathered accesses. This > typically > + /// happens at full expression level. The set is cleared after emitting > the > + /// diagnostics. > + void DiagnoseMisalignedMembers(); > + > + /// \brief This function checks if the expression is in the sef of > potentially > + /// misaligned members and it is converted to some pointer type T with > lower > + /// or equal alignment requirements. If so it removes it. This is used > when > + /// we do not want to diagnose such misaligned access (e.g. in > conversions to void*). > + void DiscardMisalignedMemberAddress(const Type *T, Expr *E); > + > + /// \brief This function calls Action when it determines that E > designates a > + /// misaligned member due to the packed attribute. This is used to emit > + /// local diagnostics like in reference binding. > + void RefersToMemberWithReducedAlignment( > + Expr *E, > + std::function<void(Expr *, RecordDecl *, ValueDecl *, CharUnits)> > Action); > }; > > /// \brief RAII object that enters a new expression evaluation context. > > Modified: cfe/trunk/lib/Sema/SemaCast.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=275417&r1=275416&r2=275417&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaCast.cpp (original) > +++ cfe/trunk/lib/Sema/SemaCast.cpp Thu Jul 14 09:10:43 2016 > @@ -256,6 +256,7 @@ Sema::BuildCXXNamedCast(SourceLocation O > Op.CheckConstCast(); > if (Op.SrcExpr.isInvalid()) > return ExprError(); > + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); > } > return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType, > Op.ValueKind, Op.SrcExpr.get(), > DestTInfo, > @@ -279,6 +280,7 @@ Sema::BuildCXXNamedCast(SourceLocation O > Op.CheckReinterpretCast(); > if (Op.SrcExpr.isInvalid()) > return ExprError(); > + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); > } > return Op.complete(CXXReinterpretCastExpr::Create(Context, > Op.ResultType, > Op.ValueKind, Op.Kind, > Op.SrcExpr.get(), > @@ -291,6 +293,7 @@ Sema::BuildCXXNamedCast(SourceLocation O > Op.CheckStaticCast(); > if (Op.SrcExpr.isInvalid()) > return ExprError(); > + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); > } > > return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType, > > Modified: cfe/trunk/lib/Sema/SemaChecking.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=275417&r1=275416&r2=275417&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) > +++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Jul 14 09:10:43 2016 > @@ -8302,6 +8302,8 @@ void CheckImplicitConversion(Sema &S, Ex > > DiagnoseNullConversion(S, E, T, CC); > > + S.DiscardMisalignedMemberAddress(Target, E); > + > if (!Source->isIntegerType() || !Target->isIntegerType()) > return; > > @@ -9371,6 +9373,7 @@ void Sema::CheckCompletedExpr(Expr *E, S > CheckUnsequencedOperations(E); > if (!IsConstexpr && !E->isValueDependent()) > CheckForIntOverflow(E); > + DiagnoseMisalignedMembers(); > } > > void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, > @@ -10916,3 +10919,67 @@ void Sema::CheckArgumentWithTypeTag(cons > << 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)); > +} > + > > Modified: cfe/trunk/lib/Sema/SemaExpr.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=275417&r1=275416&r2=275417&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) > +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jul 14 09:10:43 2016 > @@ -6001,7 +6001,9 @@ Sema::ActOnCastExpr(Scope *S, SourceLoca > CheckTollFreeBridgeCast(castType, CastExpr); > > CheckObjCBridgeRelatedCast(castType, CastExpr); > - > + > + DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr); > + > return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); > } > > @@ -10534,6 +10536,8 @@ QualType Sema::CheckAddressOfOperand(Exp > if (op->getType()->isObjCObjectType()) > return Context.getObjCObjectPointerType(op->getType()); > > + CheckAddressOfPackedMember(op); > + > return Context.getPointerType(op->getType()); > } > > > Modified: cfe/trunk/lib/Sema/SemaInit.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=275417&r1=275416&r2=275417&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaInit.cpp (original) > +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Jul 14 09:10:43 2016 > @@ -6457,6 +6457,15 @@ InitializationSequence::Perform(Sema &S, > ExtendingEntity->getDecl()); > > CheckForNullPointerDereference(S, CurInit.get()); > + > + S.RefersToMemberWithReducedAlignment(CurInit.get(), [&](Expr *E, > + RecordDecl > *RD, > + ValueDecl > *MD, > + CharUnits) { > + S.Diag(Kind.getLocation(), > diag::err_binding_reference_to_packed_member) > + << MD << RD << E->getSourceRange(); > + }); > + > break; > > case SK_BindReferenceToTemporary: { > @@ -6645,12 +6654,16 @@ InitializationSequence::Perform(Sema &S, > getAssignmentAction(Entity), CCK); > if (CurInitExprRes.isInvalid()) > return ExprError(); > + > + S.DiscardMisalignedMemberAddress(Step->Type.getTypePtr(), > CurInit.get()); > + > CurInit = CurInitExprRes; > > if (Step->Kind == SK_ConversionSequenceNoNarrowing && > S.getLangOpts().CPlusPlus && !CurInit.get()->isValueDependent()) > DiagnoseNarrowingInInitList(S, *Step->ICS, SourceType, > Entity.getType(), > CurInit.get()); > + > break; > } > > > Added: cfe/trunk/test/Sema/address-packed-member-memops.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/address-packed-member-memops.c?rev=275417&view=auto > > ============================================================================== > --- cfe/trunk/test/Sema/address-packed-member-memops.c (added) > +++ cfe/trunk/test/Sema/address-packed-member-memops.c Thu Jul 14 09:10:43 > 2016 > @@ -0,0 +1,26 @@ > +// RUN: %clang_cc1 -fsyntax-only -verify %s > +// expected-no-diagnostics > + > +struct B { > + int x, y, z, w; > +} b; > + > +struct __attribute__((packed)) A { > + struct B b; > +} a; > + > +typedef __typeof__(sizeof(int)) size_t; > + > +void *memcpy(void *dest, const void *src, size_t n); > +int memcmp(const void *s1, const void *s2, size_t n); > +void *memmove(void *dest, const void *src, size_t n); > +void *memset(void *s, int c, size_t n); > + > +int x; > + > +void foo(void) { > + memcpy(&a.b, &b, sizeof(b)); > + memmove(&a.b, &b, sizeof(b)); > + memset(&a.b, 0, sizeof(b)); > + x = memcmp(&a.b, &b, sizeof(b)); > +} > > Added: cfe/trunk/test/Sema/address-packed.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/address-packed.c?rev=275417&view=auto > > ============================================================================== > --- cfe/trunk/test/Sema/address-packed.c (added) > +++ cfe/trunk/test/Sema/address-packed.c Thu Jul 14 09:10:43 2016 > @@ -0,0 +1,160 @@ > +// RUN: %clang_cc1 -fsyntax-only -verify %s > +extern void f1(int *); > +extern void f2(char *); > + > +struct Ok { > + char c; > + int x; > +}; > + > +struct __attribute__((packed)) Arguable { > + char c0; > + int x; > + char c1; > +}; > + > +union __attribute__((packed)) UnionArguable { > + char c; > + int x; > +}; > + > +typedef struct Arguable ArguableT; > + > +struct Arguable *get_arguable(); > + > +void to_void(void *); > + > +void g0(void) { > + { > + struct Ok ok; > + f1(&ok.x); // no-warning > + f2(&ok.c); // no-warning > + } > + { > + struct Arguable 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 > + void *p = &arguable.x; // no-warning; > + to_void(p); > + } > + { > + 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 > + } > + { > + 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 > + } > + { > + 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 > + } > + { > + 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 > + } > +} > + > +struct S1 { > + char c; > + int i __attribute__((packed)); > +}; > + > +int *g1(struct S1 *s1) { > + return &s1->i; // expected-warning {{packed member 'i' of class or > structure 'S1'}} > +} > + > +struct S2_i { > + int i; > +}; > +struct __attribute__((packed)) S2 { > + char c; > + struct S2_i inner; > +}; > + > +int *g2(struct S2 *s2) { > + return &s2->inner.i; // expected-warning {{packed member 'inner' of > class or structure 'S2'}} > +} > + > +struct S2_a { > + char c; > + struct S2_i inner __attribute__((packed)); > +}; > + > +int *g2_a(struct S2_a *s2_a) { > + return &s2_a->inner.i; // expected-warning {{packed member 'inner' of > class or structure 'S2_a'}} > +} > + > +struct __attribute__((packed)) S3 { > + char c; > + struct { > + int i; > + } inner; > +}; > + > +int *g3(struct S3 *s3) { > + return &s3->inner.i; // expected-warning {{packed member 'inner' of > class or structure 'S3'}} > +} > + > +struct S4 { > + char c; > + struct __attribute__((packed)) { > + int i; > + } inner; > +}; > + > +int *g4(struct S4 *s4) { > + return &s4->inner.i; // expected-warning {{packed member 'i' of class > or structure 'S4::(anonymous)'}} > +} > + > +struct S5 { > + char c; > + struct { > + char c1; > + int i __attribute__((packed)); > + } inner; > +}; > + > +int *g5(struct S5 *s5) { > + return &s5->inner.i; // expected-warning {{packed member 'i' of class > or structure 'S5::(anonymous)'}} > +} > + > +struct __attribute__((packed, aligned(2))) AlignedTo2 { > + int x; > +}; > + > +char *g6(struct AlignedTo2 *s) { > + return (char *)&s->x; // no-warning > +} > + > +struct __attribute__((packed, aligned(2))) AlignedTo2Bis { > + int x; > +}; > + > +struct AlignedTo2Bis* g7(struct AlignedTo2 *s) > +{ > + return (struct AlignedTo2Bis*)&s->x; // no-warning > +} > > Added: cfe/trunk/test/SemaCXX/address-packed-member-memops.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/address-packed-member-memops.cpp?rev=275417&view=auto > > ============================================================================== > --- cfe/trunk/test/SemaCXX/address-packed-member-memops.cpp (added) > +++ cfe/trunk/test/SemaCXX/address-packed-member-memops.cpp Thu Jul 14 > 09:10:43 2016 > @@ -0,0 +1,28 @@ > +// RUN: %clang_cc1 -fsyntax-only -verify %s > +// expected-no-diagnostics > + > +struct B { > + int x, y, z, w; > +} b; > + > +struct __attribute__((packed)) A { > + struct B b; > +} a; > + > +typedef __typeof__(sizeof(int)) size_t; > + > +extern "C" { > +void *memcpy(void *dest, const void *src, size_t n); > +int memcmp(const void *s1, const void *s2, size_t n); > +void *memmove(void *dest, const void *src, size_t n); > +void *memset(void *s, int c, size_t n); > +} > + > +int x; > + > +void foo() { > + memcpy(&a.b, &b, sizeof(b)); > + memmove(&a.b, &b, sizeof(b)); > + memset(&a.b, 0, sizeof(b)); > + x = memcmp(&a.b, &b, sizeof(b)); > +} > > Added: cfe/trunk/test/SemaCXX/address-packed.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/address-packed.cpp?rev=275417&view=auto > > ============================================================================== > --- cfe/trunk/test/SemaCXX/address-packed.cpp (added) > +++ cfe/trunk/test/SemaCXX/address-packed.cpp Thu Jul 14 09:10:43 2016 > @@ -0,0 +1,118 @@ > +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s > +extern void f1(int *); > +extern void f2(char *); > + > +struct __attribute__((packed)) Arguable { > + int x; > + char c; > + static void foo(); > +}; > + > +extern void f3(void()); > + > +namespace Foo { > +struct __attribute__((packed)) Arguable { > + char c; > + int x; > + static void foo(); > +}; > +} > + > +struct Arguable *get_arguable(); > + > +void f4(int &); > + > +void to_void(void *); > + > +template <typename... T> > +void sink(T...); > + > +void g0() { > + { > + Foo::Arguable arguable; > + f1(&arguable.x); // expected-warning {{packed member 'x' of class > or structure 'Foo::Arguable'}} > + f2(&arguable.c); // no-warning > + f3(&arguable.foo); // no-warning > + > + int &w = arguable.x; // expected-error {{binding reference to packed > member 'x' of class or structure 'Foo::Arguable'}} > + sink(w); > + f4(arguable.x); // expected-error {{binding reference to packed > member 'x' of class or structure 'Foo::Arguable'}} > + > + to_void(&arguable.x); // no-warning > + void *p1 = &arguable.x; // no-warning > + void *p2 = static_cast<void *>(&arguable.x); // no-warning > + void *p3 = reinterpret_cast<void *>(&arguable.x); // no-warning > + void *p4 = (void *)&arguable.x; // no-warning > + sink(p1, p2, p3, p4); > + } > + { > + Arguable arguable1; > + Arguable &arguable(arguable1); > + f1(&arguable.x); // expected-warning {{packed member 'x' of class > or structure 'Arguable'}} > + f2(&arguable.c); // no-warning > + f3(&arguable.foo); // no-warning > + } > + { > + Arguable *arguable1; > + Arguable *&arguable(arguable1); > + f1(&arguable->x); // expected-warning {{packed member 'x' of class > or structure 'Arguable'}} > + f2(&arguable->c); // no-warning > + f3(&arguable->foo); // no-warning > + } > +} > + > +struct __attribute__((packed)) A { > + int x; > + char c; > + > + int *f0() { > + return &this->x; // expected-warning {{packed member 'x' of class or > structure 'A'}} > + } > + > + int *g0() { > + return &x; // expected-warning {{packed member 'x' of class or > structure 'A'}} > + } > + > + char *h0() { > + return &c; // no-warning > + } > +}; > + > +struct B : A { > + int *f1() { > + return &this->x; // expected-warning {{packed member 'x' of class or > structure 'A'}} > + } > + > + int *g1() { > + return &x; // expected-warning {{packed member 'x' of class or > structure 'A'}} > + } > + > + char *h1() { > + return &c; // no-warning > + } > +}; > + > +template <typename Ty> > +class __attribute__((packed)) S { > + Ty X; > + > +public: > + const Ty *get() const { > + return &X; // expected-warning {{packed member 'X' of class or > structure 'S<int>'}} > + // expected-warning@-1 {{packed member 'X' of class or > structure 'S<float>'}} > + } > +}; > + > +template <typename Ty> > +void h(Ty *); > + > +void g1() { > + S<int> s1; > + s1.get(); // expected-note {{in instantiation of member function > 'S<int>::get'}} > + > + S<char> s2; > + s2.get(); > + > + S<float> s3; > + s3.get(); // expected-note {{in instantiation of member function > 'S<float>::get'}} > +} > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits