Skip to content

Commit b8e8ff3

Browse files
authored
[Clang] Implement diagnostics for why is_empty is false (#145044)
Expands on #141911
1 parent a945fb1 commit b8e8ff3

File tree

5 files changed

+198
-2
lines changed

5 files changed

+198
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ Improvements to Clang's diagnostics
647647
#GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
648648
#GH36703, #GH32903, #GH23312, #GH69874.
649649

650-
650+
651651
Improvements to Clang's time-trace
652652
----------------------------------
653653

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,8 @@ def note_unsatisfied_trait
17671767
: Note<"%0 is not %enum_select<TraitName>{"
17681768
"%TriviallyRelocatable{trivially relocatable}|"
17691769
"%Replaceable{replaceable}|"
1770-
"%TriviallyCopyable{trivially copyable}"
1770+
"%TriviallyCopyable{trivially copyable}|"
1771+
"%Empty{empty}"
17711772
"}1">;
17721773

17731774
def note_unsatisfied_trait_reason
@@ -1787,6 +1788,10 @@ def note_unsatisfied_trait_reason
17871788
"%NonReplaceableField{has a non-replaceable member %1 of type %2}|"
17881789
"%NTCBase{has a non-trivially-copyable base %1}|"
17891790
"%NTCField{has a non-trivially-copyable member %1 of type %2}|"
1791+
"%NonEmptyMember{has a non-static data member %1 of type %2}|"
1792+
"%VirtualFunction{has a virtual function %1}|"
1793+
"%NonEmptyBase{has a base class %1 that is not empty}|"
1794+
"%NonZeroLengthField{field %1 is a non-zero-length bit-field}|"
17901795
"%DeletedDtr{has a %select{deleted|user-provided}1 destructor}|"
17911796
"%UserProvidedCtr{has a user provided %select{copy|move}1 "
17921797
"constructor}|"

clang/lib/Sema/SemaTypeTraits.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
19581958
.Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
19591959
.Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
19601960
.Case("is_assignable", TypeTrait::BTT_IsAssignable)
1961+
.Case("is_empty", TypeTrait::UTT_IsEmpty)
19611962
.Default(std::nullopt);
19621963
}
19631964

@@ -2313,6 +2314,74 @@ static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc,
23132314
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
23142315
}
23152316

2317+
static void DiagnoseIsEmptyReason(Sema &S, SourceLocation Loc,
2318+
const CXXRecordDecl *D) {
2319+
// Non-static data members (ignore zero-width bit‐fields).
2320+
for (const auto *Field : D->fields()) {
2321+
if (Field->isZeroLengthBitField())
2322+
continue;
2323+
if (Field->isBitField()) {
2324+
S.Diag(Loc, diag::note_unsatisfied_trait_reason)
2325+
<< diag::TraitNotSatisfiedReason::NonZeroLengthField << Field
2326+
<< Field->getSourceRange();
2327+
continue;
2328+
}
2329+
S.Diag(Loc, diag::note_unsatisfied_trait_reason)
2330+
<< diag::TraitNotSatisfiedReason::NonEmptyMember << Field
2331+
<< Field->getType() << Field->getSourceRange();
2332+
}
2333+
2334+
// Virtual functions.
2335+
for (const auto *M : D->methods()) {
2336+
if (M->isVirtual()) {
2337+
S.Diag(Loc, diag::note_unsatisfied_trait_reason)
2338+
<< diag::TraitNotSatisfiedReason::VirtualFunction << M
2339+
<< M->getSourceRange();
2340+
break;
2341+
}
2342+
}
2343+
2344+
// Virtual bases and non-empty bases.
2345+
for (const auto &B : D->bases()) {
2346+
const auto *BR = B.getType()->getAsCXXRecordDecl();
2347+
if (!BR || BR->isInvalidDecl())
2348+
continue;
2349+
if (B.isVirtual()) {
2350+
S.Diag(Loc, diag::note_unsatisfied_trait_reason)
2351+
<< diag::TraitNotSatisfiedReason::VBase << B.getType()
2352+
<< B.getSourceRange();
2353+
}
2354+
if (!BR->isEmpty()) {
2355+
S.Diag(Loc, diag::note_unsatisfied_trait_reason)
2356+
<< diag::TraitNotSatisfiedReason::NonEmptyBase << B.getType()
2357+
<< B.getSourceRange();
2358+
}
2359+
}
2360+
}
2361+
2362+
static void DiagnoseIsEmptyReason(Sema &S, SourceLocation Loc, QualType T) {
2363+
// Emit primary "not empty" diagnostic.
2364+
S.Diag(Loc, diag::note_unsatisfied_trait) << T << diag::TraitName::Empty;
2365+
2366+
// While diagnosing is_empty<T>, we want to look at the actual type, not a
2367+
// reference or an array of it. So we need to massage the QualType param to
2368+
// strip refs and arrays.
2369+
if (T->isReferenceType())
2370+
S.Diag(Loc, diag::note_unsatisfied_trait_reason)
2371+
<< diag::TraitNotSatisfiedReason::Ref;
2372+
T = T.getNonReferenceType();
2373+
2374+
if (auto *AT = S.Context.getAsArrayType(T))
2375+
T = AT->getElementType();
2376+
2377+
if (auto *D = T->getAsCXXRecordDecl()) {
2378+
if (D->hasDefinition()) {
2379+
DiagnoseIsEmptyReason(S, Loc, D);
2380+
S.Diag(D->getLocation(), diag::note_defined_here) << D;
2381+
}
2382+
}
2383+
}
2384+
23162385
void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
23172386
E = E->IgnoreParenImpCasts();
23182387
if (E->containsErrors())
@@ -2336,6 +2405,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
23362405
case BTT_IsAssignable:
23372406
DiagnoseNonAssignableReason(*this, E->getBeginLoc(), Args[0], Args[1]);
23382407
break;
2408+
case UTT_IsEmpty:
2409+
DiagnoseIsEmptyReason(*this, E->getBeginLoc(), Args[0]);
2410+
break;
23392411
default:
23402412
break;
23412413
}

clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ struct is_assignable {
2828

2929
template <typename T, typename U>
3030
constexpr bool is_assignable_v = __is_assignable(T, U);
31+
32+
template <typename T>
33+
struct is_empty {
34+
static constexpr bool value = __is_empty(T);
35+
};
36+
template <typename T>
37+
constexpr bool is_empty_v = __is_empty(T);
3138
#endif
3239

3340
#ifdef STD2
@@ -63,6 +70,15 @@ using is_assignable = __details_is_assignable<T, U>;
6370

6471
template <typename T, typename U>
6572
constexpr bool is_assignable_v = __is_assignable(T, U);
73+
74+
template <typename T>
75+
struct __details_is_empty {
76+
static constexpr bool value = __is_empty(T);
77+
};
78+
template <typename T>
79+
using is_empty = __details_is_empty<T>;
80+
template <typename T>
81+
constexpr bool is_empty_v = __is_empty(T);
6682
#endif
6783

6884

@@ -101,6 +117,13 @@ using is_assignable = __details_is_assignable<T, U>;
101117

102118
template <typename T, typename U>
103119
constexpr bool is_assignable_v = is_assignable<T, U>::value;
120+
121+
template <typename T>
122+
struct __details_is_empty : bool_constant<__is_empty(T)> {};
123+
template <typename T>
124+
using is_empty = __details_is_empty<T>;
125+
template <typename T>
126+
constexpr bool is_empty_v = is_empty<T>::value;
104127
#endif
105128

106129
}
@@ -127,6 +150,18 @@ static_assert(std::is_trivially_copyable_v<int&>);
127150
// expected-note@-1 {{'int &' is not trivially copyable}} \
128151
// expected-note@-1 {{because it is a reference type}}
129152

153+
static_assert(!std::is_empty<int>::value);
154+
155+
static_assert(std::is_empty<int&>::value);
156+
// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_empty<int &>::value'}} \
157+
// expected-note@-1 {{'int &' is not empty}} \
158+
// expected-note@-1 {{because it is a reference type}}
159+
static_assert(std::is_empty_v<int&>);
160+
// expected-error@-1 {{static assertion failed due to requirement 'std::is_empty_v<int &>'}} \
161+
// expected-note@-1 {{'int &' is not empty}} \
162+
// expected-note@-1 {{because it is a reference type}}
163+
164+
130165
static_assert(std::is_assignable<int&, int>::value);
131166

132167
static_assert(std::is_assignable<int&, void>::value);
@@ -162,6 +197,15 @@ namespace test_namespace {
162197
static_assert(is_assignable_v<int&, void>);
163198
// expected-error@-1 {{static assertion failed due to requirement 'is_assignable_v<int &, void>'}} \
164199
// expected-error@-1 {{assigning to 'int' from incompatible type 'void'}}
200+
201+
static_assert(is_empty<int&>::value);
202+
// expected-error-re@-1 {{static assertion failed due to requirement '{{.*}}is_empty<int &>::value'}} \
203+
// expected-note@-1 {{'int &' is not empty}} \
204+
// expected-note@-1 {{because it is a reference type}}
205+
static_assert(is_empty_v<int&>);
206+
// expected-error@-1 {{static assertion failed due to requirement 'is_empty_v<int &>'}} \
207+
// expected-note@-1 {{'int &' is not empty}} \
208+
// expected-note@-1 {{because it is a reference type}}
165209
}
166210

167211

clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,78 @@ static_assert(__is_assignable(C1, C1));
559559
// expected-note@#ama-C1 {{implicitly declared private here}} \
560560
// expected-note@#a-C1 {{'C1' defined here}}
561561
}
562+
563+
namespace is_empty_tests {
564+
// Non-static data member.
565+
struct A { int x; }; // #e-A
566+
static_assert(__is_empty(A));
567+
// expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::A)'}} \
568+
// expected-note@-1 {{'A' is not empty}} \
569+
// expected-note@-1 {{because it has a non-static data member 'x' of type 'int'}} \
570+
// expected-note@#e-A {{'A' defined here}}
571+
572+
// Reference member.
573+
struct R {int &r; }; // #e-R
574+
static_assert(__is_empty(R));
575+
// expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::R)'}} \
576+
// expected-note@-1 {{'R' is not empty}} \
577+
// expected-note@-1 {{because it has a non-static data member 'r' of type 'int &'}} \
578+
// expected-note@#e-R {{'R' defined here}}
579+
580+
// Virtual function.
581+
struct VirtualFunc {virtual void f(); }; // #e-VirtualFunc
582+
static_assert(__is_empty(VirtualFunc));
583+
// expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::VirtualFunc)'}} \
584+
// expected-note@-1 {{'VirtualFunc' is not empty}} \
585+
// expected-note@-1 {{because it has a virtual function 'f'}} \
586+
// expected-note@#e-VirtualFunc {{'VirtualFunc' defined here}}
587+
588+
// Virtual base class.
589+
struct EB {};
590+
struct VB: virtual EB {}; // #e-VB
591+
static_assert(__is_empty(VB));
592+
// expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::VB)'}} \
593+
// expected-note@-1 {{'VB' is not empty}} \
594+
// expected-note@-1 {{because it has a virtual base 'EB'}} \
595+
// expected-note@#e-VB {{'VB' defined here}}
596+
597+
// Non-empty base class.
598+
struct Base { int b; }; // #e-Base
599+
struct Derived : Base {}; // #e-Derived
600+
static_assert(__is_empty(Derived));
601+
// expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::Derived)'}} \
602+
// expected-note@-1 {{'Derived' is not empty}} \
603+
// expected-note@-1 {{because it has a base class 'Base' that is not empty}} \
604+
// expected-note@#e-Derived {{'Derived' defined here}}
605+
606+
// Combination of the above.
607+
struct Multi : Base, virtual EB { // #e-Multi
608+
int z;
609+
virtual void g();
610+
};
611+
static_assert(__is_empty(Multi));
612+
// expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::Multi)'}} \
613+
// expected-note@-1 {{'Multi' is not empty}} \
614+
// expected-note@-1 {{because it has a non-static data member 'z' of type 'int'}} \
615+
// expected-note@-1 {{because it has a virtual function 'g'}} \
616+
// expected-note@-1 {{because it has a base class 'Base' that is not empty}} \
617+
// expected-note@-1 {{because it has a virtual base 'EB'}} \
618+
// expected-note@#e-Multi {{'Multi' defined here}}
619+
620+
// Zero-width bit-field.
621+
struct BitField { int : 0; }; // #e-BitField
622+
static_assert(__is_empty(BitField)); // no diagnostics
623+
624+
// Dependent bit-field width.
625+
template <int N>
626+
struct DependentBitField { int : N; }; // #e-DependentBitField
627+
628+
static_assert(__is_empty(DependentBitField<0>)); // no diagnostics
629+
630+
static_assert(__is_empty(DependentBitField<2>));
631+
// expected-error@-1 {{static assertion failed due to requirement '__is_empty(is_empty_tests::DependentBitField<2>)'}} \
632+
// expected-note@-1 {{'DependentBitField<2>' is not empty}} \
633+
// expected-note@-1 {{because it field '' is a non-zero-length bit-field}} \
634+
// expected-note@#e-DependentBitField {{'DependentBitField<2>' defined here}}
635+
636+
}

0 commit comments

Comments
 (0)