-
Notifications
You must be signed in to change notification settings - Fork 13.9k
[libc++][Clang] Added explanation why is_constructible evaluated to false. Updated the diagnostics checks in libc++ tests. #144220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…uated to false. " (llvm#144127)" This reverts commit 90d98a3.
@llvm/pr-subscribers-clang Author: Shamshura Egor (egorshamshura) ChangesReverts #144127 Patch is 29.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144220.diff 14 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8fe7ad6138aa0..95d24e9f1e6b5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1767,7 +1767,8 @@ def note_unsatisfied_trait
: Note<"%0 is not %enum_select<TraitName>{"
"%TriviallyRelocatable{trivially relocatable}|"
"%Replaceable{replaceable}|"
- "%TriviallyCopyable{trivially copyable}"
+ "%TriviallyCopyable{trivially copyable}|"
+ "%Constructible{constructible with provided types}"
"}1">;
def note_unsatisfied_trait_reason
@@ -1797,7 +1798,10 @@ def note_unsatisfied_trait_reason
"%DeletedAssign{has a deleted %select{copy|move}1 "
"assignment operator}|"
"%UnionWithUserDeclaredSMF{is a union with a user-declared "
- "%sub{select_special_member_kind}1}"
+ "%sub{select_special_member_kind}1}|"
+ "%FunctionType{is a function type}|"
+ "%CVVoidType{is a cv void type}|"
+ "%IncompleteArrayType{is an incomplete array type}"
"}0">;
def warn_consteval_if_always_true : Warning<
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 1738ab4466001..fa31fee4708fd 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TypeTraits.h"
@@ -1947,6 +1949,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
TypeTrait::UTT_IsCppTriviallyRelocatable)
.Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
.Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
+ .Case("is_constructible", TypeTrait::TT_IsConstructible)
.Default(std::nullopt);
}
@@ -1983,8 +1986,16 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) {
Trait = StdNameToTypeTrait(Name);
if (!Trait)
return std::nullopt;
- for (const auto &Arg : VD->getTemplateArgs().asArray())
- Args.push_back(Arg.getAsType());
+ for (const auto &Arg : VD->getTemplateArgs().asArray()) {
+ if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
+ for (const auto &InnerArg : Arg.pack_elements())
+ Args.push_back(InnerArg.getAsType());
+ } else if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
+ Args.push_back(Arg.getAsType());
+ } else {
+ llvm_unreachable("Unexpected kind");
+ }
+ }
return {{Trait.value(), std::move(Args)}};
}
@@ -2257,6 +2268,60 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
}
}
+static void DiagnoseNonConstructibleReason(
+ Sema &SemaRef, SourceLocation Loc,
+ const llvm::SmallVector<clang::QualType, 1> &Ts) {
+ if (Ts.empty()) {
+ return;
+ }
+
+ bool ContainsVoid = false;
+ for (const QualType &ArgTy : Ts) {
+ ContainsVoid |= ArgTy->isVoidType();
+ }
+
+ if (ContainsVoid)
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::CVVoidType;
+
+ QualType T = Ts[0];
+ if (T->isFunctionType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::FunctionType;
+
+ if (T->isIncompleteArrayType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::IncompleteArrayType;
+
+ const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+ if (!D || D->isInvalidDecl() || !D->hasDefinition())
+ return;
+
+ llvm::BumpPtrAllocator OpaqueExprAllocator;
+ SmallVector<Expr *, 2> ArgExprs;
+ ArgExprs.reserve(Ts.size() - 1);
+ for (unsigned I = 1, N = Ts.size(); I != N; ++I) {
+ QualType ArgTy = Ts[I];
+ if (ArgTy->isObjectType() || ArgTy->isFunctionType())
+ ArgTy = SemaRef.Context.getRValueReferenceType(ArgTy);
+ ArgExprs.push_back(
+ new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
+ OpaqueValueExpr(Loc, ArgTy.getNonLValueExprType(SemaRef.Context),
+ Expr::getValueKindForType(ArgTy)));
+ }
+
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ Sema::ContextRAII TUContext(SemaRef,
+ SemaRef.Context.getTranslationUnitDecl());
+ InitializedEntity To(InitializedEntity::InitializeTemporary(T));
+ InitializationKind InitKind(InitializationKind::CreateDirect(Loc, Loc, Loc));
+ InitializationSequence Init(SemaRef, To, InitKind, ArgExprs);
+
+ Init.Diagnose(SemaRef, To, InitKind, ArgExprs);
+ SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
SourceLocation Loc, QualType T) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
@@ -2296,6 +2361,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
case UTT_IsTriviallyCopyable:
DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
break;
+ case TT_IsConstructible:
+ DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
+ break;
default:
break;
}
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 5b4551ba0143b..9948075852135 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -564,11 +564,12 @@ struct A {
namespace ex2 {
#if __cplusplus >= 201103L
struct Bar {
- struct Baz {
+ struct Baz { // #cwg1890-Baz
int a = 0;
};
static_assert(__is_constructible(Baz), "");
// since-cxx11-error@-1 {{static assertion failed due to requirement '__is_constructible(cwg1890::ex2::Bar::Baz)'}}
+ // since-cxx11-note@#cwg1890-Baz {{'Baz' defined here}}
};
#endif
} // namespace ex2
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index 7cb71e075d50e..46c3670848529 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -80,21 +80,30 @@ struct ImplicitlyCopyable {
static_assert(__is_constructible(ImplicitlyCopyable, const ImplicitlyCopyable&));
-struct Movable {
+struct Movable { // #Movable
template <typename T>
requires __is_constructible(Movable, T) // #err-self-constraint-1
- explicit Movable(T op) noexcept; // #1
- Movable(Movable&&) noexcept = default; // #2
+ explicit Movable(T op) noexcept; // #Movable1
+ Movable(Movable&&) noexcept = default; // #Movable2
};
static_assert(__is_constructible(Movable, Movable&&));
static_assert(__is_constructible(Movable, const Movable&));
-// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}}
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}} \
+// expected-error@-1 {{call to implicitly-deleted copy constructor of 'Movable'}} \
+// expected-note@#Movable {{'Movable' defined here}} \
+// expected-note@#Movable {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Movable' for 1st argument}} \
+// expected-note@#Movable2 {{copy constructor is implicitly deleted because 'Movable' has a user-declared move constructor}} \
+// expected-note@#Movable2 {{candidate constructor not viable: no known conversion from 'int' to 'Movable' for 1st argument}} \
+// expected-note@#Movable1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+
static_assert(__is_constructible(Movable, int));
-// expected-error@-1{{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error@-1 {{no matching constructor for initialization of 'Movable'}} \
// expected-note@-1 2{{}}
// expected-error@#err-self-constraint-1{{satisfaction of constraint '__is_constructible(Movable, T)' depends on itself}}
// expected-note@#err-self-constraint-1 4{{}}
+// expected-note@#Movable {{'Movable' defined here}}
template <typename T>
struct Members {
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 329b611110c1d..a403a0450607a 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -20,6 +20,14 @@ struct is_trivially_copyable {
template <typename T>
constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template <typename... Args>
+struct is_constructible {
+ static constexpr bool value = __is_constructible(Args...);
+};
+
+template <typename... Args>
+constexpr bool is_constructible_v = __is_constructible(Args...);
#endif
#ifdef STD2
@@ -44,6 +52,17 @@ using is_trivially_copyable = __details_is_trivially_copyable<T>;
template <typename T>
constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template <typename... Args>
+struct __details_is_constructible{
+ static constexpr bool value = __is_constructible(Args...);
+};
+
+template <typename... Args>
+using is_constructible = __details_is_constructible<Args...>;
+
+template <typename... Args>
+constexpr bool is_constructible_v = __is_constructible(Args...);
#endif
@@ -73,6 +92,15 @@ using is_trivially_copyable = __details_is_trivially_copyable<T>;
template <typename T>
constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
+
+template <typename... Args>
+struct __details_is_constructible : bool_constant<__is_constructible(Args...)> {};
+
+template <typename... Args>
+using is_constructible = __details_is_constructible<Args...>;
+
+template <typename... Args>
+constexpr bool is_constructible_v = is_constructible<Args...>::value;
#endif
}
@@ -100,6 +128,15 @@ static_assert(std::is_trivially_copyable_v<int&>);
// expected-note@-1 {{because it is a reference type}}
+static_assert(std::is_constructible<int, int>::value);
+
+static_assert(std::is_constructible<void>::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_constructible<void>::value'}} \
+// expected-note@-1 {{because it is a cv void type}}
+static_assert(std::is_constructible_v<void>);
+// expected-error@-1 {{static assertion failed due to requirement 'std::is_constructible_v<void>'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
namespace test_namespace {
using namespace std;
static_assert(is_trivially_relocatable<int&>::value);
@@ -119,6 +156,13 @@ namespace test_namespace {
// expected-error@-1 {{static assertion failed due to requirement 'is_trivially_copyable_v<int &>'}} \
// expected-note@-1 {{'int &' is not trivially copyable}} \
// expected-note@-1 {{because it is a reference type}}
+
+ static_assert(is_constructible<void>::value);
+ // expected-error-re@-1 {{static assertion failed due to requirement '{{.*}}is_constructible<void>::value'}} \
+ // expected-note@-1 {{because it is a cv void type}}
+ static_assert(is_constructible_v<void>);
+ // expected-error@-1 {{static assertion failed due to requirement 'is_constructible_v<void>'}} \
+ // expected-note@-1 {{because it is a cv void type}}
}
@@ -139,6 +183,15 @@ concept C2 = std::is_trivially_copyable_v<T>; // #concept4
template <C2 T> void g2(); // #cand4
+template <typename... Args>
+requires std::is_constructible<Args...>::value void f3(); // #cand5
+
+template <typename... Args>
+concept C3 = std::is_constructible_v<Args...>; // #concept6
+
+template <C3 T> void g3(); // #cand6
+
+
void test() {
f<int&>();
// expected-error@-1 {{no matching function for call to 'f'}} \
@@ -169,6 +222,19 @@ void test() {
// expected-note@#concept4 {{because 'std::is_trivially_copyable_v<int &>' evaluated to false}} \
// expected-note@#concept4 {{'int &' is not trivially copyable}} \
// expected-note@#concept4 {{because it is a reference type}}
+
+ f3<void>();
+ // expected-error@-1 {{no matching function for call to 'f3'}} \
+ // expected-note@#cand5 {{candidate template ignored: constraints not satisfied [with Args = <void>]}} \
+ // expected-note-re@#cand5 {{because '{{.*}}is_constructible<void>::value' evaluated to false}} \
+ // expected-note@#cand5 {{because it is a cv void type}}
+
+ g3<void>();
+ // expected-error@-1 {{no matching function for call to 'g3'}} \
+ // expected-note@#cand6 {{candidate template ignored: constraints not satisfied [with T = void]}} \
+ // expected-note@#cand6 {{because 'void' does not satisfy 'C3'}} \
+ // expected-note@#concept6 {{because 'std::is_constructible_v<void>' evaluated to false}} \
+ // expected-note@#concept6 {{because it is a cv void type}}
}
}
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index a8c78f6304ca9..d0b3f294fbcab 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -488,3 +488,65 @@ static_assert(__is_trivially_copyable(S12));
// expected-note@-1 {{'S12' is not trivially copyable}} \
// expected-note@#tc-S12 {{'S12' defined here}}
}
+
+namespace constructible {
+
+struct S1 { // #c-S1
+ S1(int); // #cc-S1
+};
+static_assert(__is_constructible(S1, char*));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, char *)'}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S1'}} \
+// expected-note@#c-S1 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'char *' to 'const S1' for 1st argument}} \
+// expected-note@#c-S1 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'char *' to 'S1' for 1st argument}} \
+// expected-note@#cc-S1 {{candidate constructor not viable: no known conversion from 'char *' to 'int' for 1st argument; dereference the argument with *}} \
+// expected-note@#c-S1 {{'S1' defined here}}
+
+struct S2 { // #c-S2
+ S2(int, float, double); // #cc-S2
+};
+static_assert(__is_constructible(S2, float));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'float' to 'const S2' for 1st argument}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'float' to 'S2' for 1st argument}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
+// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 1 was provided}} \
+// expected-note@#c-S2 {{'S2' defined here}}
+
+static_assert(__is_constructible(S2, float, void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float, void)'}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided}} \
+// expected-note@-1{{because it is a cv void type}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
+// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 2 were provided}} \
+// expected-note@#c-S2 {{'S2' defined here}}
+
+static_assert(__is_constructible(int[]));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int[])'}} \
+// expected-note@-1 {{because it is an incomplete array type}}
+
+static_assert(__is_constructible(void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(void, void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void, void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(const void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(const void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(volatile void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(volatile void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(int ()));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int ())'}} \
+// expected-note@-1 {{because it is a function type}}
+
+static_assert(__is_constructible(void (int, float)));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void (int, float))'}} \
+// expected-note@-1 {{because it is a function type}}
+}
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
index c46ab633295c1..101e7f56e1580 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
@@ -55,6 +55,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -74,6 +75,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -94,6 +96,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -113,6 +116,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
index af1fa53307960..fa0932f1a75e9 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
@@ -55,6 +55,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The ...
[truncated]
|
@llvm/pr-subscribers-libcxx Author: Shamshura Egor (egorshamshura) ChangesReverts #144127 Patch is 29.19 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144220.diff 14 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8fe7ad6138aa0..95d24e9f1e6b5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1767,7 +1767,8 @@ def note_unsatisfied_trait
: Note<"%0 is not %enum_select<TraitName>{"
"%TriviallyRelocatable{trivially relocatable}|"
"%Replaceable{replaceable}|"
- "%TriviallyCopyable{trivially copyable}"
+ "%TriviallyCopyable{trivially copyable}|"
+ "%Constructible{constructible with provided types}"
"}1">;
def note_unsatisfied_trait_reason
@@ -1797,7 +1798,10 @@ def note_unsatisfied_trait_reason
"%DeletedAssign{has a deleted %select{copy|move}1 "
"assignment operator}|"
"%UnionWithUserDeclaredSMF{is a union with a user-declared "
- "%sub{select_special_member_kind}1}"
+ "%sub{select_special_member_kind}1}|"
+ "%FunctionType{is a function type}|"
+ "%CVVoidType{is a cv void type}|"
+ "%IncompleteArrayType{is an incomplete array type}"
"}0">;
def warn_consteval_if_always_true : Warning<
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 1738ab4466001..fa31fee4708fd 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -11,7 +11,9 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/TypeTraits.h"
@@ -1947,6 +1949,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
TypeTrait::UTT_IsCppTriviallyRelocatable)
.Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
.Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
+ .Case("is_constructible", TypeTrait::TT_IsConstructible)
.Default(std::nullopt);
}
@@ -1983,8 +1986,16 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) {
Trait = StdNameToTypeTrait(Name);
if (!Trait)
return std::nullopt;
- for (const auto &Arg : VD->getTemplateArgs().asArray())
- Args.push_back(Arg.getAsType());
+ for (const auto &Arg : VD->getTemplateArgs().asArray()) {
+ if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
+ for (const auto &InnerArg : Arg.pack_elements())
+ Args.push_back(InnerArg.getAsType());
+ } else if (Arg.getKind() == TemplateArgument::ArgKind::Type) {
+ Args.push_back(Arg.getAsType());
+ } else {
+ llvm_unreachable("Unexpected kind");
+ }
+ }
return {{Trait.value(), std::move(Args)}};
}
@@ -2257,6 +2268,60 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
}
}
+static void DiagnoseNonConstructibleReason(
+ Sema &SemaRef, SourceLocation Loc,
+ const llvm::SmallVector<clang::QualType, 1> &Ts) {
+ if (Ts.empty()) {
+ return;
+ }
+
+ bool ContainsVoid = false;
+ for (const QualType &ArgTy : Ts) {
+ ContainsVoid |= ArgTy->isVoidType();
+ }
+
+ if (ContainsVoid)
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::CVVoidType;
+
+ QualType T = Ts[0];
+ if (T->isFunctionType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::FunctionType;
+
+ if (T->isIncompleteArrayType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::IncompleteArrayType;
+
+ const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+ if (!D || D->isInvalidDecl() || !D->hasDefinition())
+ return;
+
+ llvm::BumpPtrAllocator OpaqueExprAllocator;
+ SmallVector<Expr *, 2> ArgExprs;
+ ArgExprs.reserve(Ts.size() - 1);
+ for (unsigned I = 1, N = Ts.size(); I != N; ++I) {
+ QualType ArgTy = Ts[I];
+ if (ArgTy->isObjectType() || ArgTy->isFunctionType())
+ ArgTy = SemaRef.Context.getRValueReferenceType(ArgTy);
+ ArgExprs.push_back(
+ new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>())
+ OpaqueValueExpr(Loc, ArgTy.getNonLValueExprType(SemaRef.Context),
+ Expr::getValueKindForType(ArgTy)));
+ }
+
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ Sema::ContextRAII TUContext(SemaRef,
+ SemaRef.Context.getTranslationUnitDecl());
+ InitializedEntity To(InitializedEntity::InitializeTemporary(T));
+ InitializationKind InitKind(InitializationKind::CreateDirect(Loc, Loc, Loc));
+ InitializationSequence Init(SemaRef, To, InitKind, ArgExprs);
+
+ Init.Diagnose(SemaRef, To, InitKind, ArgExprs);
+ SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
SourceLocation Loc, QualType T) {
SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
@@ -2296,6 +2361,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
case UTT_IsTriviallyCopyable:
DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
break;
+ case TT_IsConstructible:
+ DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
+ break;
default:
break;
}
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 5b4551ba0143b..9948075852135 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -564,11 +564,12 @@ struct A {
namespace ex2 {
#if __cplusplus >= 201103L
struct Bar {
- struct Baz {
+ struct Baz { // #cwg1890-Baz
int a = 0;
};
static_assert(__is_constructible(Baz), "");
// since-cxx11-error@-1 {{static assertion failed due to requirement '__is_constructible(cwg1890::ex2::Bar::Baz)'}}
+ // since-cxx11-note@#cwg1890-Baz {{'Baz' defined here}}
};
#endif
} // namespace ex2
diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
index 7cb71e075d50e..46c3670848529 100644
--- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
+++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp
@@ -80,21 +80,30 @@ struct ImplicitlyCopyable {
static_assert(__is_constructible(ImplicitlyCopyable, const ImplicitlyCopyable&));
-struct Movable {
+struct Movable { // #Movable
template <typename T>
requires __is_constructible(Movable, T) // #err-self-constraint-1
- explicit Movable(T op) noexcept; // #1
- Movable(Movable&&) noexcept = default; // #2
+ explicit Movable(T op) noexcept; // #Movable1
+ Movable(Movable&&) noexcept = default; // #Movable2
};
static_assert(__is_constructible(Movable, Movable&&));
static_assert(__is_constructible(Movable, const Movable&));
-// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}}
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}} \
+// expected-error@-1 {{call to implicitly-deleted copy constructor of 'Movable'}} \
+// expected-note@#Movable {{'Movable' defined here}} \
+// expected-note@#Movable {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const Movable' for 1st argument}} \
+// expected-note@#Movable2 {{copy constructor is implicitly deleted because 'Movable' has a user-declared move constructor}} \
+// expected-note@#Movable2 {{candidate constructor not viable: no known conversion from 'int' to 'Movable' for 1st argument}} \
+// expected-note@#Movable1 {{candidate template ignored: constraints not satisfied [with T = int]}}
+
static_assert(__is_constructible(Movable, int));
-// expected-error@-1{{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error@-1 {{no matching constructor for initialization of 'Movable'}} \
// expected-note@-1 2{{}}
// expected-error@#err-self-constraint-1{{satisfaction of constraint '__is_constructible(Movable, T)' depends on itself}}
// expected-note@#err-self-constraint-1 4{{}}
+// expected-note@#Movable {{'Movable' defined here}}
template <typename T>
struct Members {
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 329b611110c1d..a403a0450607a 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -20,6 +20,14 @@ struct is_trivially_copyable {
template <typename T>
constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template <typename... Args>
+struct is_constructible {
+ static constexpr bool value = __is_constructible(Args...);
+};
+
+template <typename... Args>
+constexpr bool is_constructible_v = __is_constructible(Args...);
#endif
#ifdef STD2
@@ -44,6 +52,17 @@ using is_trivially_copyable = __details_is_trivially_copyable<T>;
template <typename T>
constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template <typename... Args>
+struct __details_is_constructible{
+ static constexpr bool value = __is_constructible(Args...);
+};
+
+template <typename... Args>
+using is_constructible = __details_is_constructible<Args...>;
+
+template <typename... Args>
+constexpr bool is_constructible_v = __is_constructible(Args...);
#endif
@@ -73,6 +92,15 @@ using is_trivially_copyable = __details_is_trivially_copyable<T>;
template <typename T>
constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
+
+template <typename... Args>
+struct __details_is_constructible : bool_constant<__is_constructible(Args...)> {};
+
+template <typename... Args>
+using is_constructible = __details_is_constructible<Args...>;
+
+template <typename... Args>
+constexpr bool is_constructible_v = is_constructible<Args...>::value;
#endif
}
@@ -100,6 +128,15 @@ static_assert(std::is_trivially_copyable_v<int&>);
// expected-note@-1 {{because it is a reference type}}
+static_assert(std::is_constructible<int, int>::value);
+
+static_assert(std::is_constructible<void>::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 'std::{{.*}}is_constructible<void>::value'}} \
+// expected-note@-1 {{because it is a cv void type}}
+static_assert(std::is_constructible_v<void>);
+// expected-error@-1 {{static assertion failed due to requirement 'std::is_constructible_v<void>'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
namespace test_namespace {
using namespace std;
static_assert(is_trivially_relocatable<int&>::value);
@@ -119,6 +156,13 @@ namespace test_namespace {
// expected-error@-1 {{static assertion failed due to requirement 'is_trivially_copyable_v<int &>'}} \
// expected-note@-1 {{'int &' is not trivially copyable}} \
// expected-note@-1 {{because it is a reference type}}
+
+ static_assert(is_constructible<void>::value);
+ // expected-error-re@-1 {{static assertion failed due to requirement '{{.*}}is_constructible<void>::value'}} \
+ // expected-note@-1 {{because it is a cv void type}}
+ static_assert(is_constructible_v<void>);
+ // expected-error@-1 {{static assertion failed due to requirement 'is_constructible_v<void>'}} \
+ // expected-note@-1 {{because it is a cv void type}}
}
@@ -139,6 +183,15 @@ concept C2 = std::is_trivially_copyable_v<T>; // #concept4
template <C2 T> void g2(); // #cand4
+template <typename... Args>
+requires std::is_constructible<Args...>::value void f3(); // #cand5
+
+template <typename... Args>
+concept C3 = std::is_constructible_v<Args...>; // #concept6
+
+template <C3 T> void g3(); // #cand6
+
+
void test() {
f<int&>();
// expected-error@-1 {{no matching function for call to 'f'}} \
@@ -169,6 +222,19 @@ void test() {
// expected-note@#concept4 {{because 'std::is_trivially_copyable_v<int &>' evaluated to false}} \
// expected-note@#concept4 {{'int &' is not trivially copyable}} \
// expected-note@#concept4 {{because it is a reference type}}
+
+ f3<void>();
+ // expected-error@-1 {{no matching function for call to 'f3'}} \
+ // expected-note@#cand5 {{candidate template ignored: constraints not satisfied [with Args = <void>]}} \
+ // expected-note-re@#cand5 {{because '{{.*}}is_constructible<void>::value' evaluated to false}} \
+ // expected-note@#cand5 {{because it is a cv void type}}
+
+ g3<void>();
+ // expected-error@-1 {{no matching function for call to 'g3'}} \
+ // expected-note@#cand6 {{candidate template ignored: constraints not satisfied [with T = void]}} \
+ // expected-note@#cand6 {{because 'void' does not satisfy 'C3'}} \
+ // expected-note@#concept6 {{because 'std::is_constructible_v<void>' evaluated to false}} \
+ // expected-note@#concept6 {{because it is a cv void type}}
}
}
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index a8c78f6304ca9..d0b3f294fbcab 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -488,3 +488,65 @@ static_assert(__is_trivially_copyable(S12));
// expected-note@-1 {{'S12' is not trivially copyable}} \
// expected-note@#tc-S12 {{'S12' defined here}}
}
+
+namespace constructible {
+
+struct S1 { // #c-S1
+ S1(int); // #cc-S1
+};
+static_assert(__is_constructible(S1, char*));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, char *)'}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S1'}} \
+// expected-note@#c-S1 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'char *' to 'const S1' for 1st argument}} \
+// expected-note@#c-S1 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'char *' to 'S1' for 1st argument}} \
+// expected-note@#cc-S1 {{candidate constructor not viable: no known conversion from 'char *' to 'int' for 1st argument; dereference the argument with *}} \
+// expected-note@#c-S1 {{'S1' defined here}}
+
+struct S2 { // #c-S2
+ S2(int, float, double); // #cc-S2
+};
+static_assert(__is_constructible(S2, float));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'float' to 'const S2' for 1st argument}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'float' to 'S2' for 1st argument}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
+// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 1 was provided}} \
+// expected-note@#c-S2 {{'S2' defined here}}
+
+static_assert(__is_constructible(S2, float, void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float, void)'}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided}} \
+// expected-note@#c-S2 {{candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided}} \
+// expected-note@-1{{because it is a cv void type}} \
+// expected-error@-1 {{no matching constructor for initialization of 'S2'}} \
+// expected-note@#cc-S2 {{candidate constructor not viable: requires 3 arguments, but 2 were provided}} \
+// expected-note@#c-S2 {{'S2' defined here}}
+
+static_assert(__is_constructible(int[]));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int[])'}} \
+// expected-note@-1 {{because it is an incomplete array type}}
+
+static_assert(__is_constructible(void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(void, void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void, void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(const void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(const void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(volatile void));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(volatile void)'}} \
+// expected-note@-1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(int ()));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(int ())'}} \
+// expected-note@-1 {{because it is a function type}}
+
+static_assert(__is_constructible(void (int, float)));
+// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void (int, float))'}} \
+// expected-note@-1 {{because it is a function type}}
+}
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
index c46ab633295c1..101e7f56e1580 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/and_then.mandates.verify.cpp
@@ -55,6 +55,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -74,6 +75,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -94,6 +96,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
@@ -113,6 +116,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
+ // expected-error@*:* {{excess elements in struct initializer}}
}
// !std::is_same_v<U:error_type, E>
diff --git a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
index af1fa53307960..fa0932f1a75e9 100644
--- a/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
+++ b/libcxx/test/libcxx/utilities/expected/expected.expected/or_else.mandates.verify.cpp
@@ -55,6 +55,7 @@ void test() {
// expected-error-re@*:* {{static assertion failed {{.*}}The ...
[truncated]
|
Hi, @AaronBallman! I noticed that the libc++ tests are not using the latest version of my code. How can I run them with the latest version? Thank you! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, @AaronBallman! I noticed that the libc++ tests are not using the latest version of my code. How can I run them with the latest version? Thank you!
They are being run with the current trunk, but also with older versions of Clang, because libc++ supports older versions. Assuming the changes are actually correct, you should be able to simply use expected-error 0-1
to work around the different diagnostic behaviour in different Clang versions.
@@ -55,6 +55,7 @@ void test() { | |||
// expected-error-re@*:* {{static assertion failed {{.*}}The result of f(value()) must be a specialization of std::expected}} | |||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}} | |||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}} | |||
// expected-error@*:* {{excess elements in struct initializer}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks fishy. Why are there more errors now? I though this should only add notes explaining what happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was discussed here: #143309 (comment)
As I understand it, this is a temporary solution.
Thanks, I get it! |
// expected-error-re@*:* 0-1{{call to deleted constructor of{{.*}}}} | ||
// expected-error-re@*:* 0-1{{call to deleted constructor of{{.*}}}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did these diagnostics go away?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In older versions of Clang, there were 4 errors displayed: {{call to deleted constructor of{{.*}}}}
, but in the new version there are 6 errors. When I added {{call to deleted constructor of 'MoveOnly'}}
, one of the errors {{call to deleted constructor of{{.*}}}}
was taken away, so I needed to add "0-1" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the total number of diagnostics stays the same, can't we just keep the expected-error
the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I guess we can.. Sorry
// expected-error-re@array:* 0-1{{{{(call to implicitly-deleted copy constructor of 'MoveOnly')|(call to deleted constructor of 'MoveOnly')}}}} | ||
// expected-error@array:* 0-1{{call to deleted constructor of 'MoveOnly'}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question here and below: Did the diagnostics disappear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same thing as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The libc++ changes LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you update the title/description to reflect the entire change (ie reuse the title/description of the previous PR)? Otherwise LGTM
Thanks for fixing the libc++ tests
I have changed title and added description. How can I rerun job? |
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)