Skip to content

Commit e476f96

Browse files
[libc++][Clang] Added explanation why is_constructible evaluated to false. Updated the diagnostics checks in libc++ tests. (#144220)
Added explanation why a is constructible evaluated to false. Also fixed problem with ExtractTypeTraitFromExpression. In case std::is_xxx_v<> with variadic pack it tries to get template argument, but fails in expression Arg.getAsType() due to Arg.getKind() == TemplateArgument::ArgKind::Pack, but not TemplateArgument::ArgKind::Type. Reverts #144127 Fixies #143309 (comment)
1 parent a73daf4 commit e476f96

File tree

14 files changed

+239
-13
lines changed

14 files changed

+239
-13
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1812,7 +1812,10 @@ def note_unsatisfied_trait_reason
18121812
"%DeletedAssign{has a deleted %select{copy|move}1 "
18131813
"assignment operator}|"
18141814
"%UnionWithUserDeclaredSMF{is a union with a user-declared "
1815-
"%sub{select_special_member_kind}1}"
1815+
"%sub{select_special_member_kind}1}|"
1816+
"%FunctionType{is a function type}|"
1817+
"%CVVoidType{is a cv void type}|"
1818+
"%IncompleteArrayType{is an incomplete array type}"
18161819
"}0">;
18171820

18181821
def warn_consteval_if_always_true : Warning<

clang/lib/Sema/SemaTypeTraits.cpp

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "clang/AST/DeclCXX.h"
14+
#include "clang/AST/TemplateBase.h"
1415
#include "clang/AST/Type.h"
16+
#include "clang/Basic/DiagnosticIDs.h"
1517
#include "clang/Basic/DiagnosticParse.h"
1618
#include "clang/Basic/DiagnosticSema.h"
1719
#include "clang/Basic/TypeTraits.h"
@@ -1963,6 +1965,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
19631965
.Case("is_assignable", TypeTrait::BTT_IsAssignable)
19641966
.Case("is_empty", TypeTrait::UTT_IsEmpty)
19651967
.Case("is_standard_layout", TypeTrait::UTT_IsStandardLayout)
1968+
.Case("is_constructible", TypeTrait::TT_IsConstructible)
19661969
.Default(std::nullopt);
19671970
}
19681971

@@ -1999,8 +2002,16 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) {
19992002
Trait = StdNameToTypeTrait(Name);
20002003
if (!Trait)
20012004
return std::nullopt;
2002-
for (const auto &Arg : VD->getTemplateArgs().asArray())
2003-
Args.push_back(Arg.getAsType());
2005+
for (const auto &Arg : VD->getTemplateArgs().asArray()) {
2006+
if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
2007+
for (const auto &InnerArg : Arg.pack_elements())
2008+
Args.push_back(InnerArg.getAsType());
2009+
} else if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
2010+
Args.push_back(Arg.getAsType());
2011+
} else {
2012+
llvm_unreachable("Unexpected kind");
2013+
}
2014+
}
20042015
return {{Trait.value(), std::move(Args)}};
20052016
}
20062017

@@ -2273,6 +2284,60 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
22732284
}
22742285
}
22752286

2287+
static void DiagnoseNonConstructibleReason(
2288+
Sema &SemaRef, SourceLocation Loc,
2289+
const llvm::SmallVector<clang::QualType, 1> &Ts) {
2290+
if (Ts.empty()) {
2291+
return;
2292+
}
2293+
2294+
bool ContainsVoid = false;
2295+
for (const QualType &ArgTy : Ts) {
2296+
ContainsVoid |= ArgTy->isVoidType();
2297+
}
2298+
2299+
if (ContainsVoid)
2300+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2301+
<< diag::TraitNotSatisfiedReason::CVVoidType;
2302+
2303+
QualType T = Ts[0];
2304+
if (T->isFunctionType())
2305+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2306+
<< diag::TraitNotSatisfiedReason::FunctionType;
2307+
2308+
if (T->isIncompleteArrayType())
2309+
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
2310+
<< diag::TraitNotSatisfiedReason::IncompleteArrayType;
2311+
2312+
const CXXRecordDecl *D = T->getAsCXXRecordDecl();
2313+
if (!D || D->isInvalidDecl() || !D->hasDefinition())
2314+
return;
2315+
2316+
llvm::BumpPtrAllocator OpaqueExprAllocator;
2317+
SmallVector<Expr *, 2> ArgExprs;
2318+
ArgExprs.reserve(Ts.size() - 1);
2319+
for (unsigned I = 1, N = Ts.size(); I != N; ++I) {
2320+
QualType ArgTy = Ts[I];
2321+
if (ArgTy->isObjectType() || ArgTy->isFunctionType())
2322+
ArgTy = SemaRef.Context.getRValueReferenceType(ArgTy);
2323+
ArgExprs.push_back(
2324+
new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
2325+
OpaqueValueExpr(Loc, ArgTy.getNonLValueExprType(SemaRef.Context),
2326+
Expr::getValueKindForType(ArgTy)));
2327+
}
2328+
2329+
EnterExpressionEvaluationContext Unevaluated(
2330+
SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
2331+
Sema::ContextRAII TUContext(SemaRef,
2332+
SemaRef.Context.getTranslationUnitDecl());
2333+
InitializedEntity To(InitializedEntity::InitializeTemporary(T));
2334+
InitializationKind InitKind(InitializationKind::CreateDirect(Loc, Loc, Loc));
2335+
InitializationSequence Init(SemaRef, To, InitKind, ArgExprs);
2336+
2337+
Init.Diagnose(SemaRef, To, InitKind, ArgExprs);
2338+
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
2339+
}
2340+
22762341
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
22772342
SourceLocation Loc, QualType T) {
22782343
SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
@@ -2559,6 +2624,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
25592624
case UTT_IsStandardLayout:
25602625
DiagnoseNonStandardLayoutReason(*this, E->getBeginLoc(), Args[0]);
25612626
break;
2627+
case TT_IsConstructible:
2628+
DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
2629+
break;
25622630
default:
25632631
break;
25642632
}

clang/test/CXX/drs/cwg18xx.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,12 @@ struct A {
564564
namespace ex2 {
565565
#if __cplusplus >= 201103L
566566
struct Bar {
567-
struct Baz {
567+
struct Baz { // #cwg1890-Baz
568568
int a = 0;
569569
};
570570
static_assert(__is_constructible(Baz), "");
571571
// since-cxx11-error@-1 {{static assertion failed due to requirement '__is_constructible(cwg1890::ex2::Bar::Baz)'}}
572+
// since-cxx11-note@#cwg1890-Baz {{'Baz' defined here}}
572573
};
573574
#endif
574575
} // namespace ex2

clang/test/SemaCXX/overload-resolution-deferred-templates.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,30 @@ struct ImplicitlyCopyable {
8080
static_assert(__is_constructible(ImplicitlyCopyable, const ImplicitlyCopyable&));
8181

8282

83-
struct Movable {
83+
struct Movable { // #Movable
8484
template <typename T>
8585
requires __is_constructible(Movable, T) // #err-self-constraint-1
86-
explicit Movable(T op) noexcept; // #1
87-
Movable(Movable&&) noexcept = default; // #2
86+
explicit Movable(T op) noexcept; // #Movable1
87+
Movable(Movable&&) noexcept = default; // #Movable2
8888
};
8989
static_assert(__is_constructible(Movable, Movable&&));
9090
static_assert(__is_constructible(Movable, const Movable&));
91-
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}}
91+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}} \
92+
// expected-error@-1 {{call to implicitly-deleted copy constructor of 'Movable'}} \
93+
// expected-note@#Movable {{'Movable' defined here}} \
94+
// expected-note@#Movable {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Movable' for 1st argument}} \
95+
// expected-note@#Movable2 {{copy constructor is implicitly deleted because 'Movable' has a user-declared move constructor}} \
96+
// expected-note@#Movable2 {{candidate constructor not viable: no known conversion from 'int' to 'Movable' for 1st argument}} \
97+
// expected-note@#Movable1 {{candidate template ignored: constraints not satisfied [with T = int]}}
98+
9299

93100
static_assert(__is_constructible(Movable, int));
94-
// expected-error@-1{{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
101+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
102+
// expected-error@-1 {{no matching constructor for initialization of 'Movable'}} \
95103
// expected-note@-1 2{{}}
96104
// expected-error@#err-self-constraint-1{{satisfaction of constraint '__is_constructible(Movable, T)' depends on itself}}
97105
// expected-note@#err-self-constraint-1 4{{}}
106+
// expected-note@#Movable {{'Movable' defined here}}
98107

99108
template <typename T>
100109
struct Members {

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

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ static constexpr bool value = __is_standard_layout(T);
4242
};
4343
template <typename T>
4444
constexpr bool is_standard_layout_v = __is_standard_layout(T);
45+
46+
template <typename... Args>
47+
struct is_constructible {
48+
static constexpr bool value = __is_constructible(Args...);
49+
};
50+
51+
template <typename... Args>
52+
constexpr bool is_constructible_v = __is_constructible(Args...);
4553
#endif
4654

4755
#ifdef STD2
@@ -97,6 +105,17 @@ template <typename T>
97105
using is_standard_layout = __details_is_standard_layout<T>;
98106
template <typename T>
99107
constexpr bool is_standard_layout_v = __is_standard_layout(T);
108+
109+
template <typename... Args>
110+
struct __details_is_constructible{
111+
static constexpr bool value = __is_constructible(Args...);
112+
};
113+
114+
template <typename... Args>
115+
using is_constructible = __details_is_constructible<Args...>;
116+
117+
template <typename... Args>
118+
constexpr bool is_constructible_v = __is_constructible(Args...);
100119
#endif
101120

102121

@@ -149,6 +168,15 @@ template <typename T>
149168
using is_standard_layout = __details_is_standard_layout<T>;
150169
template <typename T>
151170
constexpr bool is_standard_layout_v = is_standard_layout<T>::value;
171+
172+
template <typename... Args>
173+
struct __details_is_constructible : bool_constant<__is_constructible(Args...)> {};
174+
175+
template <typename... Args>
176+
using is_constructible = __details_is_constructible<Args...>;
177+
178+
template <typename... Args>
179+
constexpr bool is_constructible_v = is_constructible<Args...>::value;
152180
#endif
153181

154182
}
@@ -211,6 +239,15 @@ static_assert(std::is_assignable_v<int&, void>);
211239
// expected-error@-1 {{static assertion failed due to requirement 'std::is_assignable_v<int &, void>'}} \
212240
// expected-error@-1 {{assigning to 'int' from incompatible type 'void'}}
213241

242+
static_assert(std::is_constructible<int, int>::value);
243+
244+
static_assert(std::is_constructible<void>::value);
245+
// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_constructible<void>::value'}} \
246+
// expected-note@-1 {{because it is a cv void type}}
247+
static_assert(std::is_constructible_v<void>);
248+
// expected-error@-1 {{static assertion failed due to requirement 'std::is_constructible_v<void>'}} \
249+
// expected-note@-1 {{because it is a cv void type}}
250+
214251
namespace test_namespace {
215252
using namespace std;
216253
static_assert(is_trivially_relocatable<int&>::value);
@@ -256,6 +293,13 @@ namespace test_namespace {
256293
// expected-error@-1 {{static assertion failed due to requirement 'is_empty_v<int &>'}} \
257294
// expected-note@-1 {{'int &' is not empty}} \
258295
// expected-note@-1 {{because it is a reference type}}
296+
297+
static_assert(is_constructible<void>::value);
298+
// expected-error-re@-1 {{static assertion failed due to requirement '{{.*}}is_constructible<void>::value'}} \
299+
// expected-note@-1 {{because it is a cv void type}}
300+
static_assert(is_constructible_v<void>);
301+
// expected-error@-1 {{static assertion failed due to requirement 'is_constructible_v<void>'}} \
302+
// expected-note@-1 {{because it is a cv void type}}
259303
}
260304

261305

@@ -284,6 +328,15 @@ concept C4 = std::is_assignable_v<T, U>; // #concept8
284328

285329
template <C4<void> T> void g4(); // #cand8
286330

331+
template <typename... Args>
332+
requires std::is_constructible<Args...>::value void f3(); // #cand5
333+
334+
template <typename... Args>
335+
concept C3 = std::is_constructible_v<Args...>; // #concept6
336+
337+
template <C3 T> void g3(); // #cand6
338+
339+
287340
void test() {
288341
f<int&>();
289342
// expected-error@-1 {{no matching function for call to 'f'}} \
@@ -327,6 +380,19 @@ void test() {
327380
// expected-note@#cand8 {{because 'C4<int &, void>' evaluated to false}} \
328381
// expected-note@#concept8 {{because 'std::is_assignable_v<int &, void>' evaluated to false}} \
329382
// expected-error@#concept8 {{assigning to 'int' from incompatible type 'void'}}
383+
384+
f3<void>();
385+
// expected-error@-1 {{no matching function for call to 'f3'}} \
386+
// expected-note@#cand5 {{candidate template ignored: constraints not satisfied [with Args = <void>]}} \
387+
// expected-note-re@#cand5 {{because '{{.*}}is_constructible<void>::value' evaluated to false}} \
388+
// expected-note@#cand5 {{because it is a cv void type}}
389+
390+
g3<void>();
391+
// expected-error@-1 {{no matching function for call to 'g3'}} \
392+
// expected-note@#cand6 {{candidate template ignored: constraints not satisfied [with T = void]}} \
393+
// expected-note@#cand6 {{because 'void' does not satisfy 'C3'}} \
394+
// expected-note@#concept6 {{because 'std::is_constructible_v<void>' evaluated to false}} \
395+
// expected-note@#concept6 {{because it is a cv void type}}
330396
}
331397
}
332398

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

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,68 @@ static_assert(__is_trivially_copyable(S12));
489489
// expected-note@#tc-S12 {{'S12' defined here}}
490490
}
491491

492+
namespace constructible {
493+
494+
struct S1 { // #c-S1
495+
S1(int); // #cc-S1
496+
};
497+
static_assert(__is_constructible(S1, char*));
498+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, char *)'}} \
499+
// expected-error@-1 {{no matching constructor for initialization of 'S1'}} \
500+
// expected-note@#c-S1 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'char *' to 'const S1' for 1st argument}} \
501+
// expected-note@#c-S1 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'char *' to 'S1' for 1st argument}} \
502+
// expected-note@#cc-S1 {{candidate constructor not viable: no known conversion from 'char *' to 'int' for 1st argument; dereference the argument with *}} \
503+
// expected-note@#c-S1 {{'S1' defined here}}
504+
505+
struct S2 { // #c-S2
506+
S2(int, float, double); // #cc-S2
507+
};
508+
static_assert(__is_constructible(S2, float));
509+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \
510+
// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'float' to 'const S2' for 1st argument}} \
511+
// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'float' to 'S2' for 1st argument}} \
512+
// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
513+
// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 1 was provided}} \
514+
// expected-note@#c-S2 {{'S2' defined here}}
515+
516+
static_assert(__is_constructible(S2, float, void));
517+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float, void)'}} \
518+
// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided}} \
519+
// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided}} \
520+
// expected-note@-1{{because it is a cv void type}} \
521+
// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
522+
// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 2 were provided}} \
523+
// expected-note@#c-S2 {{'S2' defined here}}
524+
525+
static_assert(__is_constructible(int[]));
526+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int[])'}} \
527+
// expected-note@-1 {{because it is an incomplete array type}}
528+
529+
static_assert(__is_constructible(void));
530+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
531+
// expected-note@-1 {{because it is a cv void type}}
532+
533+
static_assert(__is_constructible(void, void));
534+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void, void)'}} \
535+
// expected-note@-1 {{because it is a cv void type}}
536+
537+
static_assert(__is_constructible(const void));
538+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(const void)'}} \
539+
// expected-note@-1 {{because it is a cv void type}}
540+
541+
static_assert(__is_constructible(volatile void));
542+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(volatile void)'}} \
543+
// expected-note@-1 {{because it is a cv void type}}
544+
545+
static_assert(__is_constructible(int ()));
546+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int ())'}} \
547+
// expected-note@-1 {{because it is a function type}}
548+
549+
static_assert(__is_constructible(void (int, float)));
550+
// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void (int, float))'}} \
551+
// expected-note@-1 {{because it is a function type}}
552+
}
553+
492554
namespace assignable {
493555
struct S1;
494556
static_assert(__is_assignable(S1&, const S1&));

libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ void test() {
5555
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
5656
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
5757
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
58+
// expected-error@*:* 0-1{{excess elements in struct initializer}}
5859
}
5960

6061
// !std::is_same_v<U:error_type, E>
@@ -74,6 +75,7 @@ void test() {
7475
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
7576
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
7677
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
78+
// expected-error@*:* 0-1{{excess elements in struct initializer}}
7779
}
7880

7981
// !std::is_same_v<U:error_type, E>
@@ -94,6 +96,7 @@ void test() {
9496
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
9597
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
9698
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
99+
// expected-error@*:* 0-1{{excess elements in struct initializer}}
97100
}
98101

99102
// !std::is_same_v<U:error_type, E>
@@ -113,6 +116,7 @@ void test() {
113116
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
114117
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
115118
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
119+
// expected-error@*:* 0-1{{excess elements in struct initializer}}
116120
}
117121

118122
// !std::is_same_v<U:error_type, E>

0 commit comments

Comments
 (0)