diff options
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 37 | ||||
| -rw-r--r-- | clang/lib/AST/RecordLayoutBuilder.cpp | 1 | ||||
| -rw-r--r-- | clang/test/SemaCXX/alignof.cpp | 10 |
3 files changed, 30 insertions, 18 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 9105940..b5ef5fa 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1321,24 +1321,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { // a max-field-alignment constraint (#pragma pack). So calculate // the actual alignment of the field within the struct, and then // (as we're expected to) constrain that by the alignment of the type. - if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) { - // So calculate the alignment of the field. - const ASTRecordLayout &layout = getASTRecordLayout(field->getParent()); - - // Start with the record's overall alignment. - unsigned fieldAlign = toBits(layout.getAlignment()); - - // Use the GCD of that and the offset within the record. - uint64_t offset = layout.getFieldOffset(field->getFieldIndex()); - if (offset > 0) { - // Alignment is always a power of 2, so the GCD will be a power of 2, - // which means we get to do this crazy thing instead of Euclid's. - uint64_t lowBitOfOffset = offset & (~offset + 1); - if (lowBitOfOffset < fieldAlign) - fieldAlign = static_cast<unsigned>(lowBitOfOffset); - } + if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) { + const RecordDecl *Parent = Field->getParent(); + // We can only produce a sensible answer if the record is valid. + if (!Parent->isInvalidDecl()) { + const ASTRecordLayout &Layout = getASTRecordLayout(Parent); + + // Start with the record's overall alignment. + unsigned FieldAlign = toBits(Layout.getAlignment()); + + // Use the GCD of that and the offset within the record. + uint64_t Offset = Layout.getFieldOffset(Field->getFieldIndex()); + if (Offset > 0) { + // Alignment is always a power of 2, so the GCD will be a power of 2, + // which means we get to do this crazy thing instead of Euclid's. + uint64_t LowBitOfOffset = Offset & (~Offset + 1); + if (LowBitOfOffset < FieldAlign) + FieldAlign = static_cast<unsigned>(LowBitOfOffset); + } - Align = std::min(Align, fieldAlign); + Align = std::min(Align, FieldAlign); + } } } diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 4cd05b7..c4ee565 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2468,6 +2468,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { D = D->getDefinition(); assert(D && "Cannot get layout of forward declarations!"); + assert(!D->isInvalidDecl() && "Cannot get layout of invalid decl!"); assert(D->isCompleteDefinition() && "Cannot layout type before complete!"); // Look up this layout, if already laid out, return what we have. diff --git a/clang/test/SemaCXX/alignof.cpp b/clang/test/SemaCXX/alignof.cpp index a9de1ad..ca673c4 100644 --- a/clang/test/SemaCXX/alignof.cpp +++ b/clang/test/SemaCXX/alignof.cpp @@ -9,7 +9,7 @@ struct S0 { auto test2() -> char(&)[__alignof__(x)]; // expected-error {{invalid application of 'alignof' to a field of a class still being defined}} }; -struct S1; // expected-note 5 {{forward declaration}} +struct S1; // expected-note 6 {{forward declaration}} extern S1 s1; const int test3 = __alignof__(s1); // expected-error {{invalid application of 'alignof' to an incomplete type 'S1'}} @@ -50,3 +50,11 @@ struct S4 { static const int test1 = __alignof__(S0::x); auto test2() -> char(&)[__alignof__(x)]; }; + +// Regression test for asking for the alignment of a field within an invalid +// record. +struct S5 { + S1 s; // expected-error {{incomplete type}} + int x; +}; +const int test8 = __alignof__(S5::x); |
