Index: clang/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticASTKinds.td +++ clang/include/clang/Basic/DiagnosticASTKinds.td @@ -590,4 +590,9 @@ InGroup, DefaultIgnore; def warn_unnecessary_packed : Warning< "packed attribute is unnecessary for %0">, InGroup, DefaultIgnore; + +// -Wunaligned-access +def warn_unaligned_access : Warning< + "field %1 within its parent %0 has an alignment greater than its parent " + "this may be caused by %0 being packed and can lead to unaligned accesses">, InGroup, DefaultIgnore; } Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -542,6 +542,7 @@ def OrderedCompareFunctionPointers : DiagGroup<"ordered-compare-function-pointers">; def Packed : DiagGroup<"packed">; def Padded : DiagGroup<"padded">; +def UnalignedAccess : DiagGroup<"unaligned-access">; def PessimizingMove : DiagGroup<"pessimizing-move">; def ReturnStdMove : DiagGroup<"return-std-move">; Index: clang/lib/AST/RecordLayoutBuilder.cpp =================================================================== --- clang/lib/AST/RecordLayoutBuilder.cpp +++ clang/lib/AST/RecordLayoutBuilder.cpp @@ -2021,6 +2021,7 @@ CharUnits UnpackedFieldAlign = !DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign; CharUnits UnpackedFieldOffset = FieldOffset; + CharUnits OriginalFieldAlign = UnpackedFieldAlign; if (FieldPacked) { FieldAlign = CharUnits::One(); @@ -2105,6 +2106,22 @@ // Remember max struct/class ABI-specified alignment. UnadjustedAlignment = std::max(UnadjustedAlignment, FieldAlign); UpdateAlignment(FieldAlign, UnpackedFieldAlign, PreferredAlign); + + // For checking the alignment of inner fields against + // the alignment of its parent record. + if (const RecordDecl *RD = D->getParent()) { + // Check if packed attribute or pragma pack is present. + if (RD->hasAttr() || !MaxFieldAlignment.isZero()) + if (FieldAlign < OriginalFieldAlign) + if (D->getType()->isRecordType()) { + // If the offset is a multiple of the alignment of + // the type, raise the warning. + // TODO: Takes no account the alignment of the outer struct + if (FieldOffset % OriginalFieldAlign != 0) + Diag(D->getLocation(), diag::warn_unaligned_access) + << Context.getTypeDeclType(RD) << D->getName(); + } + } } void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { Index: clang/lib/Driver/ToolChains/Arch/AArch64.h =================================================================== --- clang/lib/Driver/ToolChains/Arch/AArch64.h +++ clang/lib/Driver/ToolChains/Arch/AArch64.h @@ -22,6 +22,7 @@ void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, std::vector &Features, bool ForAS); Index: clang/lib/Driver/ToolChains/Arch/AArch64.cpp =================================================================== --- clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -219,6 +219,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, std::vector &Features, bool ForAS) { Arg *A; @@ -459,8 +460,10 @@ if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { - if (A->getOption().matches(options::OPT_mno_unaligned_access)) + if (A->getOption().matches(options::OPT_mno_unaligned_access)) { Features.push_back("+strict-align"); + CmdArgs.push_back("-Wunaligned-access"); + } } else if (Triple.isOSOpenBSD()) Features.push_back("+strict-align"); Index: clang/lib/Driver/ToolChains/Arch/ARM.cpp =================================================================== --- clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -783,6 +783,7 @@ D.Diag(diag::err_target_unsupported_unaligned) << "v8m.base"; } else Features.push_back("+strict-align"); + CmdArgs.push_back("-Wunaligned-access"); } else { // Assume pre-ARMv6 doesn't support unaligned accesses. // Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -346,7 +346,8 @@ case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Triple, Args, Features, ForAS); + aarch64::getAArch64TargetFeatures(D, Triple, Args, CmdArgs, Features, + ForAS); break; case llvm::Triple::x86: case llvm::Triple::x86_64: Index: clang/test/Sema/test-wunaligned-access.c =================================================================== --- /dev/null +++ clang/test/Sema/test-wunaligned-access.c @@ -0,0 +1,476 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -Wunaligned-access +// expected-no-diagnostics +// Set 1 +struct T1 { + char a; + int b; +}; + +struct __attribute__((packed)) U1 { + char a; + struct T1 b; + int c; +}; + +struct __attribute__((packed)) U2 { + char a; + struct T1 b __attribute__((aligned(2))); + int c; +}; + +struct __attribute__((packed)) U3 { + char a; + struct T1 b __attribute__((aligned(4))); + int c; +}; + +struct __attribute__((aligned(2))) U4 { + char a; + struct T1 b; + int c; +}; + +struct U5 { + char a; + struct T1 b; + int c; +}; + +struct U6 { + char a; + int b; + struct T1 c __attribute__((aligned(2))); +}; + +struct __attribute__((packed)) U7 { + short a; + short b; + char c; + struct T1 d; +}; + +struct U8 { + short a; + short b; + char c; + struct T1 d; +}; + +struct __attribute__((packed)) U9 { + short a; + short b; + char c; + struct T1 d __attribute__((aligned(4))); +}; + +struct __attribute__((packed)) U10 { + short a; + short b; + char c; + struct T1 d __attribute__((aligned(2))); +}; + +struct __attribute__((aligned(2))) U11 { + short a; + short b; + char c; + struct T1 d; +}; + +// Set 2 +#pragma pack(push, 1) + +struct U12 { + char a; + struct T1 b; + int c; +}; + +struct __attribute__((packed)) U13 { + char a; + struct T1 b; + int c; +}; + +struct __attribute__((packed)) U14 { + char a; + struct T1 b __attribute__((aligned(4))); + int c; +}; + +struct __attribute__((aligned(2))) U15 { + char a; + struct T1 b; + int c; +}; + +struct U16 { + char a; + char b; + short c; + struct T1 d; +}; + +struct U17 { + char a; + char b; + short c; + struct T1 d __attribute__((aligned(4))); +}; + +struct __attribute__((packed)) U18 { + char a; + short b; + struct T1 c __attribute__((aligned(4))); +}; + +struct __attribute__((aligned(4))) U19 { + char a; + struct T1 b; + int c; +}; + +struct __attribute__((aligned(4))) U20 { + char a[4]; + struct T1 b; + int c; +}; + +struct U21 { + char a; + short c; + struct T1 d; +}; + +struct U22 { + char a; + short c; + struct T1 d __attribute__((aligned(4))); +}; + +#pragma pack(pop) + +// Set 3 + +struct __attribute__((packed)) U23 { + char a; + struct T1 b; + int c; +}; + +struct U24 { + char a; + struct T1 b; + int c; +}; + +struct U25 { + char a; + char b; + short c; + struct T1 d; +}; + +#pragma pack(push, 1) + +struct U26 { + char a; + char b; + short c; + struct T1 d; +}; + +#pragma pack(pop) + +// Set 4 + +struct __attribute__((packed)) T2 { + char a; + struct T1 b; +}; + +struct T3 { + char a; + struct T1 b; +}; + +struct __attribute__((packed)) U27 { + char a; + struct T2 b; + int c; +}; + +struct U28 { + char a; + char _p[2]; + struct T2 b; + int c; +}; + +struct U29 { + char a; + struct T3 b; + int c; +}; + +struct __attribute__((packed)) U30 { + char a; + struct T3 b; + int c; +}; + +struct __attribute__((packed)) U31 { + char a; + struct T2 b __attribute__((aligned(4))); +}; + +struct __attribute__((packed)) U32 { + char a; + char b; + char c; + char d; + struct T3 e; +}; + +struct __attribute__((packed)) U33 { + char a; + char b; + char c; + char d; + struct T2 e __attribute__((aligned(4))); +}; + +struct __attribute__((packed)) U34 { + char a; + struct T1 b __attribute__((packed)); + struct T2 c; +}; + +struct __attribute__((packed)) U35 { + char a; + struct T4 { + char b; + struct T1 c; + } d; +}; + +// Set 5 + +#pragma pack(push, 1) +struct T5 { + char a; + struct T1 b; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +struct U36 { + char a; + struct T5 b; + int c; +}; + +struct U37 { + char a; + struct T3 b; + int c; +}; +#pragma pack(pop) +struct U38 { + char a; + struct T5 b __attribute__((aligned(4))); + int c; +}; + +struct U39 { + char a; +#pragma pack(push, 4) + struct T5 b; +#pragma pack(pop) + int c; +}; + +// Set 6 + +struct __attribute__((packed)) A1 { + char a; + struct T1 b; +}; + +struct A2 { + char a; + struct T1 b; +}; + +struct __attribute__((packed)) A3 { + char a; + struct T1 b __attribute__((aligned(4))); +}; + +#pragma pack(push, 1) +struct A4 { + char a; + struct T1 b; +}; + +struct A5 { + char a; + struct T1 b __attribute__((aligned(4))); +}; +#pragma pack(pop) + +struct __attribute__((packed)) A6 { + struct T1 a; +}; + +struct A7 { + char a; + struct T1 b __attribute__((packed)); +}; + +struct A8 { + char a; + char b; + short c; + struct T1 d; +}; + +struct A9 { + char a; + struct T2 b; +}; + +struct A10 { + char a; + struct T2 b __attribute__((aligned(4))); +}; + +struct __attribute__((packed)) A11 { + char a; + struct T2 b; +}; + +struct __attribute__((packed)) U40 { + char a; + struct A1 b; + int c; +}; + +struct __attribute__((packed)) U41 { + char a; + struct A3 b; + int c; +}; + +#pragma pack(push, 1) +struct U42 { + char a; + struct A1 b; + int c; +}; +#pragma pack(pop) + +struct __attribute__((packed)) U43 { + char a; + struct A9 b; + int c; +}; + +struct __attribute__((packed)) U44 { + char a; + struct A10 b; + int c; +}; + +#pragma pack(push, 1) + +struct U45 { + char a; + struct A10 b; + int c; +}; + +#pragma pack(pop) + +struct __attribute__((packed)) U46 { + char a; + struct A2 b; + int c; +}; + +struct __attribute__((packed)) U47 { + char a; + struct A8 b; + int c; +}; + +#pragma pack(push, 1) +struct U48 { + char a; + struct A8 b; + int c; +}; +#pragma pack(pop) + +struct U49 { + char a; + struct A11 b; + int c; +}; + +struct U50 { + char a; + struct A1 b; + int c; +}; + +struct U1 s1; +struct U2 s2; +struct U3 s3; +struct U4 s4; +struct U5 s5; +struct U6 s6; +struct U7 s7; +struct U8 s8; +struct U9 s9; +struct U10 s10; +struct U11 s11; +struct U12 s12; +struct U13 s13; +struct U14 s14; +struct U15 s15; +struct U16 s16; +struct U17 s17; +struct U18 s18; +struct U19 s19; +struct U20 s20; +struct U21 s21; +struct U22 s22; +struct U23 s23; +struct U24 s24; +struct U25 s25; +struct U26 s26; +struct U27 s27; +struct U28 s28; +struct U29 s29; +struct U30 s30; +struct U31 s31; +struct U32 s32; +struct U33 s33; +struct U34 s34; +struct U35 s35; +struct U36 s36; +struct U37 s37; +struct U38 s38; +struct U39 s39; +struct U40 s40; +struct U41 s41; +struct U42 s42; +struct U43 s43; +struct U44 s44; +struct U45 s45; +struct U46 s46; +struct U47 s47; +struct U48 s48; +struct U49 s49; +struct U50 s50; Index: clang/test/Sema/test-wunaligned-access.cpp =================================================================== --- /dev/null +++ clang/test/Sema/test-wunaligned-access.cpp @@ -0,0 +1,285 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only -Wunaligned-access + +// Packed-Unpacked Tests (No Pragma) + +struct T1 { + char a; + int b; +}; + +struct __attribute__((packed)) U1 // Causes warning +{ + char a; + T1 b; // expected-warning {{field b within its parent 'U1' has an alignment greater than its parent this may be caused by 'U1' being packed and can lead to unaligned accesses}} + int c; +}; + +struct __attribute__((packed)) U2 // No warning +{ + char a; + T1 b __attribute__((aligned(4))); + int c; +}; + +struct __attribute__((packed)) U3 // No warning +{ + char a; + char b; + short c; + T1 d; +}; + +struct __attribute__((packed)) U4 // No warning +{ + T1 a; + int b; +}; + +struct __attribute__((aligned(4), packed)) U5 // Causes warning +{ + char a; + T1 b; // expected-warning {{field b within its parent 'U5' has an alignment greater than its parent this may be caused by 'U5' being packed and can lead to unaligned accesses}} + int c; +}; + +struct __attribute__((aligned(4), packed)) U6 // No warning +{ + char a; + char b; + short c; + T1 d; +}; + +// Packed-Unpacked Tests with Pragma + +#pragma pack(push, 1) + +struct __attribute__((packed)) U7 // Causes warning +{ + char a; + T1 b; // expected-warning {{field b within its parent 'U7' has an alignment greater than its parent this may be caused by 'U7' being packed and can lead to unaligned accesses}} + int c; +}; + +struct __attribute__((packed)) U8 { + char a; + T1 b __attribute__((aligned(4))); // expected-warning {{field b within its parent 'U8' has an alignment greater than its parent this may be caused by 'U8' being packed and can lead to unaligned accesses}} + int c; +}; + +struct __attribute__((aligned(4))) U9 { + char a; + T1 b; // expected-warning {{field b within its parent 'U9' has an alignment greater than its parent this may be caused by 'U9' being packed and can lead to unaligned accesses}} + int c; +}; + +struct U10 { + char a; + T1 b; // expected-warning {{field b within its parent 'U10' has an alignment greater than its parent this may be caused by 'U10' being packed and can lead to unaligned accesses}} + int c; +}; + +#pragma pack(pop) + +// Packed-Packed Tests + +struct __attribute__((packed)) T2 { + char a; + int b; +}; + +struct __attribute__((packed)) U11 { + char a; + T2 b; + int c; +}; + +#pragma pack(push, 1) +struct U12 // No warning +{ + char a; + T2 b; + int c; +}; +#pragma pack(pop) + +// Unpacked-Packed Tests + +struct U13 // No warning +{ + char a; + T2 b; + int c; +}; + +struct U14 // No warning +{ + char a; + T2 b __attribute__((aligned(4))); + int c; +}; + +// Unpacked-Unpacked Test + +struct T3 { + char a; + int b; +}; + +struct U15 // No warning +{ + char a; + T3 b; + int c; +}; + +// Packed-Packed-Unpacked Test (No pragma) + +struct __attribute__((packed)) A1 { + char a; + T1 b; // expected-warning {{field b within its parent 'A1' has an alignment greater than its parent this may be caused by 'A1' being packed and can lead to unaligned accesses}} +}; + +struct __attribute__((packed)) U16 // No warning +{ + char a; + A1 b; + int c; +}; + +struct __attribute__((packed)) A2 // No warning +{ + char a; + T1 b __attribute__((aligned(4))); +}; + +struct __attribute__((packed)) U17 // Caused warning +{ + char a; + A2 b; // expected-warning {{field b within its parent 'U17' has an alignment greater than its parent this may be caused by 'U17' being packed and can lead to unaligned accesses}} + int c; +}; + +// Packed-Unpacked-Packed tests + +struct A3 { + char a; + T2 b; +}; + +struct __attribute__((packed)) U18 { + char a; + A3 b; + int c; +}; + +struct A4 { + char a; + T2 b; + int c; +}; + +#pragma pack(push, 1) +struct U19 // Caused warning +{ + char a; + A4 b; // expected-warning {{field b within its parent 'U19' has an alignment greater than its parent this may be caused by 'U19' being packed and can lead to unaligned accesses}} + int c; +}; +#pragma pack(pop) + +// Packed-Unpacked-Unpacked tests + +struct A5 { + char a; + T1 b; +}; + +struct __attribute__((packed)) U20 // Caused warning +{ + char a; + A5 b; // expected-warning {{field b within its parent 'U20' has an alignment greater than its parent this may be caused by 'U20' being packed and can lead to unaligned accesses}} + int c; +}; + +struct A6 { + char a; + T1 b; +}; + +#pragma pack(push, 1) +struct U21 // Caused warning +{ + char a; + A6 b; // expected-warning {{field b within its parent 'U21' has an alignment greater than its parent this may be caused by 'U21' being packed and can lead to unaligned accesses}} + int c; +}; +#pragma pack(pop) + +// Unpacked-Packed-Packed test + +struct __attribute__((packed)) A7 // No warning +{ + char a; + T2 b; +}; + +struct U22 // No warning +{ + char a; + A7 b; + int c; +}; + +// Unpacked-Packed-Unpacked tests + +struct __attribute__((packed)) A8 // Should cause warning +{ + char a; + T1 b; // expected-warning {{field b within its parent 'A8' has an alignment greater than its parent this may be caused by 'A8' being packed and can lead to unaligned accesses}} +}; + +struct U23 // No warning +{ + char a; + A8 b; + int c; +}; + +struct __attribute__((packed)) A9 // No warning +{ + char a; + T1 b __attribute__((aligned(4))); +}; + +struct U24 // No warning +{ + char a; + A9 b; + int c; +}; + +struct U1 s1; +struct U2 s2; +struct U3 s3; +struct U4 s4; +struct U5 s5; +struct U6 s6; +struct U7 s7; +struct U8 s8; +struct U9 s9; +struct U10 s10; +struct U11 s11; +struct U12 s12; +struct U13 s13; +struct U14 s14; +struct U15 s15; +struct U16 s16; +struct U17 s17; +struct U18 s18; +struct U19 s19; +struct U20 s20; +struct U21 s21; +struct U22 s22; +struct U23 s23; +struct U24 s24;