Skip to content

Commit a6b90f3

Browse files
committed
Added diagnostic for is_aggregate.
1 parent 5a49d52 commit a6b90f3

File tree

4 files changed

+239
-8
lines changed

4 files changed

+239
-8
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,8 @@ def note_unsatisfied_trait
17721772
"%Replaceable{replaceable}|"
17731773
"%TriviallyCopyable{trivially copyable}|"
17741774
"%Empty{empty}|"
1775-
"%StandardLayout{standard-layout}"
1775+
"%StandardLayout{standard-layout}|"
1776+
"%Aggregate{aggregate}"
17761777
"}1">;
17771778

17781779
def note_unsatisfied_trait_reason
@@ -1805,6 +1806,8 @@ def note_unsatisfied_trait_reason
18051806
"%DeletedDtr{has a %select{deleted|user-provided}1 destructor}|"
18061807
"%UserProvidedCtr{has a user provided %select{copy|move}1 "
18071808
"constructor}|"
1809+
"%UserDeclaredCtr{has a user-declared constructor}|"
1810+
"%InheritedCtr{has an inherited constructor}|"
18081811
"%DeletedCtr{has a deleted %select{copy|move}1 "
18091812
"constructor}|"
18101813
"%UserProvidedAssign{has a user provided %select{copy|move}1 "
@@ -1815,7 +1818,11 @@ def note_unsatisfied_trait_reason
18151818
"%sub{select_special_member_kind}1}|"
18161819
"%FunctionType{is a function type}|"
18171820
"%CVVoidType{is a cv void type}|"
1818-
"%IncompleteArrayType{is an incomplete array type}"
1821+
"%IncompleteArrayType{is an incomplete array type}|"
1822+
"%PrivateDirectDataMember{has a private direct data member}|"
1823+
"%ProtectedDirectDataMember{has a protected direct data member}|"
1824+
"%PrivateDirectBase{has a private direct base}|"
1825+
"%ProtectedDirectBase{has a protected direct base}"
18191826
"}0">;
18201827

18211828
def warn_consteval_if_always_true : Warning<

clang/lib/Sema/SemaTypeTraits.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,9 +2596,79 @@ static void DiagnoseNonStandardLayoutReason(Sema &SemaRef, SourceLocation Loc,
25962596
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
25972597
}
25982598

2599+
static void DiagnoseNonAggregateReason(Sema &SemaRef, SourceLocation Loc,
2600+
const CXXRecordDecl *D) {
2601+
for (const CXXConstructorDecl *Ctor : D->ctors()) {
2602+
if (Ctor->isUserProvided())
2603+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2604+
<< diag::TraitNotSatisfiedReason::UserDeclaredCtr;
2605+
if (Ctor->isInheritingConstructor())
2606+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2607+
<< diag::TraitNotSatisfiedReason::InheritedCtr;
2608+
}
2609+
2610+
for (const FieldDecl *Field : D->fields()) {
2611+
switch (Field->getAccess()) {
2612+
case AS_private:
2613+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2614+
<< diag::TraitNotSatisfiedReason::PrivateDirectDataMember;
2615+
break;
2616+
case AS_protected:
2617+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2618+
<< diag::TraitNotSatisfiedReason::ProtectedDirectDataMember;
2619+
break;
2620+
default:
2621+
break;
2622+
}
2623+
}
2624+
2625+
for (const CXXBaseSpecifier &B : D->bases()) {
2626+
if (B.isVirtual()) {
2627+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2628+
<< diag::TraitNotSatisfiedReason::VBase << B.getType()
2629+
<< B.getSourceRange();
2630+
continue;
2631+
}
2632+
switch (B.getAccessSpecifier()) {
2633+
case AS_private:
2634+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2635+
<< diag::TraitNotSatisfiedReason::PrivateDirectBase;
2636+
break;
2637+
case AS_protected:
2638+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2639+
<< diag::TraitNotSatisfiedReason::ProtectedDirectBase;
2640+
break;
2641+
default:
2642+
break;
2643+
}
2644+
}
2645+
2646+
for (const CXXMethodDecl *Method : D->methods()) {
2647+
if (Method->isVirtual()) {
2648+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2649+
<< diag::TraitNotSatisfiedReason::VirtualFunction << Method
2650+
<< Method->getSourceRange();
2651+
}
2652+
}
2653+
2654+
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
2655+
}
2656+
25992657
static void DiagnoseNonAggregateReason(Sema &SemaRef, SourceLocation Loc, QualType T) {
26002658
SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
26012659
<< T << diag::TraitName::Aggregate;
2660+
2661+
if (T->isVoidType())
2662+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2663+
<< diag::TraitNotSatisfiedReason::CVVoidType;
2664+
2665+
T = T.getNonReferenceType();
2666+
const CXXRecordDecl *D = T->getAsCXXRecordDecl();
2667+
if (!D || D->isInvalidDecl())
2668+
return;
2669+
2670+
if (D->hasDefinition())
2671+
DiagnoseNonAggregateReason(SemaRef, Loc, D);
26022672
}
26032673

26042674
void Sema::DiagnoseTypeTraitDetails(const Expr *E) {

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

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ struct is_constructible {
5050

5151
template <typename... Args>
5252
constexpr bool is_constructible_v = __is_constructible(Args...);
53+
54+
template <typename T>
55+
struct is_aggregate {
56+
static constexpr bool value = __is_aggregate(T);
57+
};
58+
59+
template <typename T>
60+
constexpr bool is_aggregate_v = __is_aggregate(T);
5361
#endif
5462

5563
#ifdef STD2
@@ -88,7 +96,7 @@ constexpr bool is_assignable_v = __is_assignable(T, U);
8896

8997
template <typename T>
9098
struct __details_is_empty {
91-
static constexpr bool value = __is_empty(T);
99+
static constexpr bool value = __is_empty(T);
92100
};
93101
template <typename T>
94102
using is_empty = __details_is_empty<T>;
@@ -97,9 +105,7 @@ constexpr bool is_empty_v = __is_empty(T);
97105

98106
template <typename T>
99107
struct __details_is_standard_layout {
100-
static constexpr bool value = __is_standard_layout(T);
101-
102-
108+
static constexpr bool value = __is_standard_layout(T);
103109
};
104110
template <typename T>
105111
using is_standard_layout = __details_is_standard_layout<T>;
@@ -116,6 +122,17 @@ using is_constructible = __details_is_constructible<Args...>;
116122

117123
template <typename... Args>
118124
constexpr bool is_constructible_v = __is_constructible(Args...);
125+
126+
template <typename T>
127+
struct __details_is_aggregate {
128+
static constexpr bool value = __is_aggregate(T);
129+
};
130+
131+
template <typename T>
132+
using is_aggregate = __details_is_aggregate<T>;
133+
134+
template <typename T>
135+
constexpr bool is_aggregate_v = __is_aggregate(T);
119136
#endif
120137

121138

@@ -173,12 +190,20 @@ template <typename... Args>
173190
struct __details_is_constructible : bool_constant<__is_constructible(Args...)> {};
174191

175192
template <typename... Args>
176-
using is_constructible = __details_is_constructible<Args...>;
193+
using is_constructible = __details_is_constructible<Args...>;
177194

178195
template <typename... Args>
179196
constexpr bool is_constructible_v = is_constructible<Args...>::value;
180-
#endif
181197

198+
template <typename T>
199+
struct __details_is_aggregate : bool_constant<__is_aggregate(T)> {};
200+
201+
template <typename T>
202+
using is_aggregate = __details_is_aggregate<T>;
203+
204+
template <typename T>
205+
constexpr bool is_aggregate_v = is_aggregate<T>::value;
206+
#endif
182207
}
183208

184209
static_assert(std::is_trivially_relocatable<int>::value);
@@ -248,6 +273,16 @@ static_assert(std::is_constructible_v<void>);
248273
// expected-error@-1 {{static assertion failed due to requirement 'std::is_constructible_v<void>'}} \
249274
// expected-note@-1 {{because it is a cv void type}}
250275

276+
static_assert(!std::is_aggregate<int>::value);
277+
278+
static_assert(std::is_aggregate<void>::value);
279+
// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_aggregate<void>::value'}} \
280+
// expected-note@-1 {{'void' is not aggregate}} \
281+
// expected-note@-1 {{because it is a cv void type}}
282+
static_assert(std::is_aggregate_v<void>);
283+
// expected-error@-1 {{static assertion failed due to requirement 'std::is_aggregate_v<void>'}} \
284+
// expected-note@-1 {{'void' is not aggregate}} \
285+
// expected-note@-1 {{because it is a cv void type}}
251286
namespace test_namespace {
252287
using namespace std;
253288
static_assert(is_trivially_relocatable<int&>::value);
@@ -300,6 +335,15 @@ namespace test_namespace {
300335
static_assert(is_constructible_v<void>);
301336
// expected-error@-1 {{static assertion failed due to requirement 'is_constructible_v<void>'}} \
302337
// expected-note@-1 {{because it is a cv void type}}
338+
339+
static_assert(std::is_aggregate<void>::value);
340+
// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_aggregate<void>::value'}} \
341+
// expected-note@-1 {{'void' is not aggregate}} \
342+
// expected-note@-1 {{because it is a cv void type}}
343+
static_assert(std::is_aggregate_v<void>);
344+
// expected-error@-1 {{static assertion failed due to requirement 'std::is_aggregate_v<void>'}} \
345+
// expected-note@-1 {{'void' is not aggregate}} \
346+
// expected-note@-1 {{because it is a cv void type}}
303347
}
304348

305349

@@ -337,6 +381,14 @@ concept C3 = std::is_constructible_v<Args...>; // #concept6
337381
template <C3 T> void g3(); // #cand6
338382

339383

384+
template <typename T>
385+
requires std::is_aggregate<T>::value void f5(); // #cand9
386+
387+
template <typename T>
388+
concept C5 = std::is_aggregate_v<T>; // #concept10
389+
390+
template <C5 T> void g5(); // #cand10
391+
340392
void test() {
341393
f<int&>();
342394
// expected-error@-1 {{no matching function for call to 'f'}} \
@@ -393,6 +445,21 @@ void test() {
393445
// expected-note@#cand6 {{because 'void' does not satisfy 'C3'}} \
394446
// expected-note@#concept6 {{because 'std::is_constructible_v<void>' evaluated to false}} \
395447
// expected-note@#concept6 {{because it is a cv void type}}
448+
449+
f5<void>();
450+
// expected-error@-1 {{no matching function for call to 'f5'}} \
451+
// expected-note@#cand9 {{candidate template ignored: constraints not satisfied [with T = void]}} \
452+
// expected-note-re@#cand9 {{because '{{.*}}is_aggregate<void>::value' evaluated to false}} \
453+
// expected-note@#cand9 {{'void' is not aggregate}} \
454+
// expected-note@#cand9 {{because it is a cv void type}}
455+
456+
g5<void>();
457+
// expected-error@-1 {{no matching function for call to 'g5'}} \
458+
// expected-note@#cand10 {{candidate template ignored: constraints not satisfied [with T = void]}} \
459+
// expected-note@#cand10 {{because 'void' does not satisfy 'C5'}} \
460+
// expected-note@#concept10 {{because 'std::is_aggregate_v<void>' evaluated to false}} \
461+
// expected-note@#concept10 {{'void' is not aggregate}} \
462+
// expected-note@#concept10 {{because it is a cv void type}}
396463
}
397464
}
398465

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

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,3 +829,90 @@ static_assert(__is_standard_layout(H)); // no diagnostics
829829
static_assert(__is_standard_layout(I)); // no diagnostics
830830
}
831831

832+
namespace is_aggregate {
833+
struct S1 { // #ag-S1
834+
S1(int);
835+
};
836+
837+
static_assert(__is_aggregate(S1));
838+
// expected-error@-1 {{static assertion failed due to requirement '__is_aggregate(is_aggregate::S1)'}} \
839+
// expected-note@-1 {{because it has a user-declared constructor}} \
840+
// expected-note@-1 {{'S1' is not aggregate}} \
841+
// expected-note@#ag-S1 {{'S1' defined here}}
842+
843+
struct B2 {
844+
B2(int);
845+
};
846+
847+
struct S2 : B2 { // #ag-S2
848+
using B2::B2;
849+
};
850+
851+
static_assert(__is_aggregate(S2));
852+
// expected-error@-1 {{static assertion failed due to requirement '__is_aggregate(is_aggregate::S2)'}} \
853+
// expected-note@-1 {{because it has an inherited constructor}} \
854+
// expected-note@-1 {{'S2' is not aggregate}} \
855+
// expected-note@#ag-S2 {{'S2' defined here}}
856+
857+
struct S3 { // #ag-S3
858+
protected:
859+
int x;
860+
};
861+
static_assert(__is_aggregate(S3));
862+
// expected-error@-1 {{static assertion failed due to requirement '__is_aggregate(is_aggregate::S3)'}} \
863+
// expected-note@-1 {{because it has a protected direct data member}} \
864+
// expected-note@-1 {{'S3' is not aggregate}} \
865+
// expected-note@#ag-S3 {{'S3' defined here}}
866+
867+
struct S4 { // #ag-S4
868+
private:
869+
int x;
870+
};
871+
static_assert(__is_aggregate(S4));
872+
// expected-error@-1 {{static assertion failed due to requirement '__is_aggregate(is_aggregate::S4)'}} \
873+
// expected-note@-1 {{because it has a private direct data member}} \
874+
// expected-note@-1 {{'S4' is not aggregate}} \
875+
// expected-note@#ag-S4 {{'S4' defined here}}
876+
877+
struct B5 {};
878+
879+
struct S5 : private B5 { // #ag-S5
880+
private:
881+
int x;
882+
};
883+
static_assert(__is_aggregate(S5));
884+
// expected-error@-1 {{static assertion failed due to requirement '__is_aggregate(is_aggregate::S5)'}} \
885+
// expected-note@-1 {{because it has a private direct base}} \
886+
// expected-note@-1 {{because it has a private direct data member}} \
887+
// expected-note@-1 {{'S5' is not aggregate}} \
888+
// expected-note@#ag-S5 {{'S5' defined here}}
889+
890+
struct B6 {};
891+
892+
struct S6 : protected B6 { // #ag-S6
893+
private:
894+
int x;
895+
};
896+
static_assert(__is_aggregate(S6));
897+
// expected-error@-1 {{static assertion failed due to requirement '__is_aggregate(is_aggregate::S6)'}} \
898+
// expected-note@-1 {{because it has a protected direct base}} \
899+
// expected-note@-1 {{because it has a private direct data member}} \
900+
// expected-note@-1 {{'S6' is not aggregate}} \
901+
// expected-note@#ag-S6 {{'S6' defined here}}
902+
903+
struct B7 {};
904+
905+
struct S7 : virtual B7 { // #ag-S7
906+
virtual void foo();
907+
908+
private:
909+
int x;
910+
};
911+
static_assert(__is_aggregate(S7));
912+
// expected-error@-1 {{static assertion failed due to requirement '__is_aggregate(is_aggregate::S7)'}} \
913+
// expected-note@-1 {{because it has a private direct data member}} \
914+
// expected-note@-1 {{because it has a virtual function 'foo'}} \
915+
// expected-note@-1 {{because it has a virtual base}} \
916+
// expected-note@-1 {{'S7' is not aggregate}} \
917+
// expected-note@#ag-S7 {{'S7' defined here}}
918+
}

0 commit comments

Comments
 (0)