It appears that GCC accepts that case. More generally, it looks like GCC suppresses the warning when the reference is a function parameter (any function, not just a copy constructor or similar). I'm not sure if that's an intentional feature or a bug, but it should be pretty easy for us to be compatible with, at least...
On Thu, Jul 14, 2016 at 5:03 PM, Reid Kleckner <r...@google.com> wrote: > I wonder if GCC accepts this: > > In file included from ../../net/tools/quic/quic_epoll_clock_test.cc:7: > In file included from > ../../net/tools/quic/test_tools/mock_epoll_server.h:16: > In file included from ../../net/tools/epoll_server/epoll_server.h:41: > ../../build/linux/debian_wheezy_amd64-sysroot/usr/include/x86_64-linux-gnu/sys/epoll.h:89:8: > error: binding reference to packed member 'data' of class or structure > 'epoll_event' > struct epoll_event > ^~~~~~~~~~~ > ../../build/linux/debian_wheezy_amd64-sysroot/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_pair.h:267:14: > note: in instantiation of function template specialization 'std::pair<long, > epoll_event>::pair<long, epoll_event>' requested here > return __pair_type(std::forward<_T1>(__x), std::forward<_T2>(__y)); > ^ > ../../net/tools/quic/test_tools/mock_epoll_server.h:69:30: note: in > instantiation of function template specialization 'std::make_pair<long &, > const epoll_event &>' requested here > event_queue_.insert(std::make_pair(time_in_usec, ee)); > > On Thu, Jul 14, 2016 at 4:54 PM, Richard Smith <rich...@metafoo.co.uk> > wrote: > >> On Thu, Jul 14, 2016 at 3:52 PM, Reid Kleckner via cfe-commits < >> cfe-commits@lists.llvm.org> wrote: >> >>> 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. >>> >> >> GCC has given an error on this since version 4.7. If there are cases that >> GCC accepts and we reject, that sounds like a bug. >> >> >>> 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 >>> >>> >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits