From: Matt Beaumont-Gay Date: Tue, 25 Jun 2013 22:19:15 +0000 (+0000) Subject: Don't try to get the layout of an invalid decl in getDeclAlign. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=147fab970c9877273e6185f0e276f376887c967f;p=clang Don't try to get the layout of an invalid decl in getDeclAlign. When the decl that we're getting alignment for is a FieldDecl, and the field's parent record is invalid, skip the actual field alignment calculation (and return 1-byte alignment in the general case). Also, assert in in getASTRecordLayout that the decl is valid. This was inspired by PR16292; see also r184581 and r184751. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184883 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 9105940076..b5ef5fa2ad 100644 --- a/lib/AST/ASTContext.cpp +++ b/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(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(lowBitOfOffset); - } + if (const FieldDecl *Field = dyn_cast(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(LowBitOfOffset); + } - Align = std::min(Align, fieldAlign); + Align = std::min(Align, FieldAlign); + } } } diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 4cd05b7f60..c4ee565c8a 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/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/test/SemaCXX/alignof.cpp b/test/SemaCXX/alignof.cpp index a9de1ad07c..ca673c42eb 100644 --- a/test/SemaCXX/alignof.cpp +++ b/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);