Skip to content

Commit

Permalink
[clang] Reject incomplete types in __is_layout_compatible() (#87869)
Browse files Browse the repository at this point in the history
This is a follow-up to #81506. As discussed in #87737, we're rejecting
incomplete types, save for exceptions listed in the C++ standard (`void`
and arrays of unknown bound). Note that arrays of unknown bound of
incomplete types are accepted.

Since we're happy with the current behavior of this intrinsic for
flexible array members
(#87737 (comment)),
I added a couple of tests for that as well.
  • Loading branch information
Endilll committed Apr 8, 2024
1 parent 125c9cf commit fd2ffc1
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6025,6 +6025,11 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
return false;
}
case BTT_IsLayoutCompatible: {
if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType())
Self.RequireCompleteType(KeyLoc, LhsT, diag::err_incomplete_type);
if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType())
Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type);

if (LhsT->isVariableArrayType() || RhsT->isVariableArrayType())
Self.Diag(KeyLoc, diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
Expand Down
39 changes: 33 additions & 6 deletions clang/test/SemaCXX/type-traits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,7 @@ enum class EnumClassLayout {};
enum EnumForward : int;
enum class EnumClassForward;

struct CStructIncomplete;
struct CStructIncomplete; // #CStructIncomplete

struct CStructNested {
int a;
Expand Down Expand Up @@ -1719,6 +1719,20 @@ struct StructWithAnonUnion3 {
} u;
};

struct CStructWithArrayAtTheEnd {
int a;
int b[4];
};

struct CStructWithFMA {
int c;
int d[];
};

struct CStructWithFMA2 {
int e;
int f[];
};

void is_layout_compatible(int n)
{
Expand Down Expand Up @@ -1800,15 +1814,28 @@ void is_layout_compatible(int n)
static_assert(__is_layout_compatible(EnumLayout, EnumClassLayout));
static_assert(__is_layout_compatible(EnumForward, EnumForward));
static_assert(__is_layout_compatible(EnumForward, EnumClassForward));
// Layout compatibility for enums might be relaxed in the future. See https://github.com/cplusplus/CWG/issues/39#issuecomment-1184791364
static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete));
// expected-error@-1 {{incomplete type 'CStructIncomplete' where a complete type is required}}
// expected-note@#CStructIncomplete {{forward declaration of 'CStructIncomplete'}}
// expected-error@-3 {{incomplete type 'CStructIncomplete' where a complete type is required}}
// expected-note@#CStructIncomplete {{forward declaration of 'CStructIncomplete'}}
static_assert(!__is_layout_compatible(CStruct, CStructIncomplete));
// expected-error@-1 {{incomplete type 'CStructIncomplete' where a complete type is required}}
// expected-note@#CStructIncomplete {{forward declaration of 'CStructIncomplete'}}
static_assert(__is_layout_compatible(CStructIncomplete[2], CStructIncomplete[2]));
// expected-error@-1 {{incomplete type 'CStructIncomplete[2]' where a complete type is required}}
// expected-note@#CStructIncomplete {{forward declaration of 'CStructIncomplete'}}
// expected-error@-3 {{incomplete type 'CStructIncomplete[2]' where a complete type is required}}
// expected-note@#CStructIncomplete {{forward declaration of 'CStructIncomplete'}}
static_assert(__is_layout_compatible(CStructIncomplete[], CStructIncomplete[]));
static_assert(!__is_layout_compatible(CStructWithArrayAtTheEnd, CStructWithFMA));
static_assert(__is_layout_compatible(CStructWithFMA, CStructWithFMA));
static_assert(__is_layout_compatible(CStructWithFMA, CStructWithFMA2));
// Layout compatibility rules for enums might be relaxed in the future. See https://github.com/cplusplus/CWG/issues/39#issuecomment-1184791364
static_assert(!__is_layout_compatible(EnumLayout, int));
static_assert(!__is_layout_compatible(EnumClassLayout, int));
static_assert(!__is_layout_compatible(EnumForward, int));
static_assert(!__is_layout_compatible(EnumClassForward, int));
// FIXME: the following should be rejected (array of unknown bound and void are the only allowed incomplete types)
static_assert(__is_layout_compatible(CStructIncomplete, CStructIncomplete));
static_assert(!__is_layout_compatible(CStruct, CStructIncomplete));
static_assert(__is_layout_compatible(CStructIncomplete[2], CStructIncomplete[2]));
}

void is_signed()
Expand Down

0 comments on commit fd2ffc1

Please sign in to comment.