[clang] [Clang] Added explanation why a is constructible evaluated to false. (PR #143309)
Shamshura Egor via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 12 12:59:16 PDT 2025
https://github.com/egorshamshura updated https://github.com/llvm/llvm-project/pull/143309
>From ed1f379144736e0c645dca87b0111f685bdd7e53 Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshuraegor at gmail.com>
Date: Sun, 8 Jun 2025 13:09:54 +0000
Subject: [PATCH 1/7] Fixed problem when std::is_xxx_v<> tries to get Argument
as type when it is pack; added is_constructible support
---
.../clang/Basic/DiagnosticSemaKinds.td | 7 +-
clang/lib/Sema/SemaTypeTraits.cpp | 35 ++++++++-
.../type-traits-unsatisfied-diags-std.cpp | 72 +++++++++++++++++++
.../SemaCXX/type-traits-unsatisfied-diags.cpp | 44 ++++++++++++
4 files changed, 154 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 5f44d503580b9..b04537d2cac3c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1765,7 +1765,8 @@ def err_user_defined_msg_constexpr : Error<
// Type traits explanations
def note_unsatisfied_trait : Note<"%0 is not %enum_select<TraitName>{"
"%TriviallyRelocatable{trivially relocatable}|"
- "%TriviallyCopyable{trivially copyable}"
+ "%TriviallyCopyable{trivially copyable}|"
+ "%Constructible{constructible with provided types}"
"}1">;
def note_unsatisfied_trait_reason
@@ -1785,7 +1786,9 @@ def note_unsatisfied_trait_reason
"%UserProvidedAssign{has a user provided %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}"
"}0">;
def warn_consteval_if_always_true : Warning<
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 330f2aa750a09..37fe965815269 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -21,6 +21,7 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaHLSL.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -1941,6 +1942,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) {
.Case("is_trivially_relocatable",
TypeTrait::UTT_IsCppTriviallyRelocatable)
.Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
+ .Case("is_constructible", TypeTrait::TT_IsConstructible)
.Default(std::nullopt);
}
@@ -1977,8 +1979,14 @@ 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());
+ }
+ if (Arg.getKind() == TemplateArgument::ArgKind::Type)
+ Args.push_back(Arg.getAsType());
+ }
return {{Trait.value(), std::move(Args)}};
}
@@ -2159,6 +2167,26 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
}
}
+static void DiagnoseNonConstructibleReason(Sema &SemaRef, SourceLocation Loc,
+ QualType T) {
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
+ << T << diag::TraitName::Constructible;
+
+ if (T->isFunctionType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::FunctionType;
+
+ if (T->isVoidType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::CVVoidType;
+
+ const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+ if (!D || D->isInvalidDecl() || !D->hasDefinition())
+ return;
+
+ 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)
@@ -2195,6 +2223,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[0]);
+ break;
default:
break;
}
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index 498e202e26265..b9ee677a1cffc 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,17 @@ static_assert(std::is_trivially_copyable_v<int&>);
// expected-note at -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 at -1 {{static assertion failed due to requirement 'std::{{.*}}is_constructible<void>::value'}} \
+// expected-note at -1 {{'void' is not constructible with provided types}} \
+// expected-note at -1 {{because it is a cv void type}}
+static_assert(std::is_constructible_v<void>);
+// expected-error at -1 {{static assertion failed due to requirement 'std::is_constructible_v<void>'}} \
+// expected-note at -1 {{'void' is not constructible with provided types}} \
+// expected-note at -1 {{because it is a cv void type}}
+
namespace test_namespace {
using namespace std;
static_assert(is_trivially_relocatable<int&>::value);
@@ -119,6 +158,15 @@ namespace test_namespace {
// expected-error at -1 {{static assertion failed due to requirement 'is_trivially_copyable_v<int &>'}} \
// expected-note at -1 {{'int &' is not trivially copyable}} \
// expected-note at -1 {{because it is a reference type}}
+
+ static_assert(is_constructible<void>::value);
+ // expected-error-re at -1 {{static assertion failed due to requirement '{{.*}}is_constructible<void>::value'}} \
+ // expected-note at -1 {{'void' is not constructible with provided types}} \
+ // expected-note at -1 {{because it is a cv void type}}
+ static_assert(is_constructible_v<void>);
+ // expected-error at -1 {{static assertion failed due to requirement 'is_constructible_v<void>'}} \
+ // expected-note at -1 {{'void' is not constructible with provided types}} \
+ // expected-note at -1 {{because it is a cv void type}}
}
@@ -139,6 +187,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 at -1 {{no matching function for call to 'f'}} \
@@ -169,5 +226,20 @@ 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 at -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 {{'void' is not constructible with provided types}} \
+ // expected-note@#cand5 {{because it is a cv void type}}
+
+ g3<void>();
+ // expected-error at -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 {{'void' is not constructible with provided types}} \
+ // 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 0256569fcca5f..9e668ef86b31a 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -290,3 +290,47 @@ static_assert(__is_trivially_copyable(S12));
// expected-note at -1 {{'S12' is not trivially copyable}} \
// expected-note@#tc-S12 {{'S12' defined here}}
}
+
+namespace constructible {
+
+struct S1 { // #c-S1
+ S1(int);
+};
+static_assert(__is_constructible(S1, int, float));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, int, float)'}} \
+// expected-note at -1 {{'S1' is not constructible with provided types}} \
+// expected-note@#c-S1 {{'S1' defined here}}
+
+struct S2 { // #c-S2
+ S2(int, float, double);
+};
+static_assert(__is_constructible(S2, float));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \
+// expected-note at -1 {{'S2' is not constructible with provided types}} \
+// expected-note@#c-S2 {{'S2' defined here}}
+
+static_assert(__is_constructible(void));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
+// expected-note at -1 {{'void' is not constructible with provided types}} \
+// expected-note at -1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(const void));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(const void)'}} \
+// expected-note at -1 {{'const void' is not constructible with provided types}} \
+// expected-note at -1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(volatile void));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(volatile void)'}} \
+// expected-note at -1 {{'volatile void' is not constructible with provided types}} \
+// expected-note at -1 {{because it is a cv void type}}
+
+static_assert(__is_constructible(int ()));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(int ())'}} \
+// expected-note at -1 {{'int ()' is not constructible with provided types}} \
+// expected-note at -1 {{because it is a function type}}
+
+static_assert(__is_constructible(void (int, float)));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(void (int, float))'}} \
+// expected-note at -1 {{'void (int, float)' is not constructible with provided types}} \
+// expected-note at -1 {{because it is a function type}}
+}
>From ef7955642a1f3f2a45ec26277021d8c7ee671e1a Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshuraegor at gmail.com>
Date: Mon, 9 Jun 2025 16:18:48 +0000
Subject: [PATCH 2/7] Updated DiagnoseNonTriviallyCopyableReason, changed tests
to current version.
---
clang/lib/Sema/SemaTypeTraits.cpp | 53 ++++++++++++++++---
.../type-traits-unsatisfied-diags-std.cpp | 6 ---
.../SemaCXX/type-traits-unsatisfied-diags.cpp | 11 +---
3 files changed, 48 insertions(+), 22 deletions(-)
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 37fe965815269..2b2e0c5d05891 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -21,7 +21,6 @@
#include "clang/Sema/Overload.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaHLSL.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -2167,11 +2166,23 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
}
}
-static void DiagnoseNonConstructibleReason(Sema &SemaRef, SourceLocation Loc,
- QualType T) {
- SemaRef.Diag(Loc, diag::note_unsatisfied_trait)
- << T << diag::TraitName::Constructible;
+static void DiagnoseNonConstructibleReason(
+ Sema &SemaRef, SourceLocation Loc,
+ const llvm::SmallVector<clang::QualType, 1> &Ts) {
+ bool CompleteTypes = true;
+ for (const auto &ArgTy : Ts) {
+ if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType())
+ continue;
+ if (ArgTy->isIncompleteType()) {
+ SemaRef.Diag(Loc, diag::err_incomplete_type_used_in_type_trait_expr)
+ << ArgTy;
+ CompleteTypes = false;
+ }
+ }
+ if (!CompleteTypes)
+ return;
+ QualType T = Ts[0];
if (T->isFunctionType())
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::FunctionType;
@@ -2183,8 +2194,36 @@ static void DiagnoseNonConstructibleReason(Sema &SemaRef, SourceLocation Loc,
const CXXRecordDecl *D = T->getAsCXXRecordDecl();
if (!D || D->isInvalidDecl() || !D->hasDefinition())
return;
-
SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+
+ 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::SFINAETrap SFINAE(SemaRef, /*ForValidityCheck=*/true);
+ 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);
+
+ if (Init.Diagnose(SemaRef, To, InitKind, ArgExprs)) {
+ auto ArgsRange = SourceRange(ArgExprs.front()->getBeginLoc(),
+ ArgExprs.back()->getEndLoc());
+
+ SemaRef.Diag(Loc, diag::err_ovl_no_viable_function_in_init) << T;
+ }
}
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
@@ -2224,7 +2263,7 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
break;
case TT_IsConstructible:
- DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args[0]);
+ DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
break;
default:
break;
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
index b9ee677a1cffc..a600c8029b768 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -132,11 +132,9 @@ static_assert(std::is_constructible<int, int>::value);
static_assert(std::is_constructible<void>::value);
// expected-error-re at -1 {{static assertion failed due to requirement 'std::{{.*}}is_constructible<void>::value'}} \
-// expected-note at -1 {{'void' is not constructible with provided types}} \
// expected-note at -1 {{because it is a cv void type}}
static_assert(std::is_constructible_v<void>);
// expected-error at -1 {{static assertion failed due to requirement 'std::is_constructible_v<void>'}} \
-// expected-note at -1 {{'void' is not constructible with provided types}} \
// expected-note at -1 {{because it is a cv void type}}
namespace test_namespace {
@@ -161,11 +159,9 @@ namespace test_namespace {
static_assert(is_constructible<void>::value);
// expected-error-re at -1 {{static assertion failed due to requirement '{{.*}}is_constructible<void>::value'}} \
- // expected-note at -1 {{'void' is not constructible with provided types}} \
// expected-note at -1 {{because it is a cv void type}}
static_assert(is_constructible_v<void>);
// expected-error at -1 {{static assertion failed due to requirement 'is_constructible_v<void>'}} \
- // expected-note at -1 {{'void' is not constructible with provided types}} \
// expected-note at -1 {{because it is a cv void type}}
}
@@ -231,7 +227,6 @@ void test() {
// expected-error at -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 {{'void' is not constructible with provided types}} \
// expected-note@#cand5 {{because it is a cv void type}}
g3<void>();
@@ -239,7 +234,6 @@ void test() {
// 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 {{'void' is not constructible with provided types}} \
// 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 9e668ef86b31a..17a9fb61ce80f 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -296,9 +296,8 @@ namespace constructible {
struct S1 { // #c-S1
S1(int);
};
-static_assert(__is_constructible(S1, int, float));
-// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, int, float)'}} \
-// expected-note at -1 {{'S1' is not constructible with provided types}} \
+static_assert(__is_constructible(S1, char*));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, char *)'}} \
// expected-note@#c-S1 {{'S1' defined here}}
struct S2 { // #c-S2
@@ -306,31 +305,25 @@ struct S2 { // #c-S2
};
static_assert(__is_constructible(S2, float));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \
-// expected-note at -1 {{'S2' is not constructible with provided types}} \
// expected-note@#c-S2 {{'S2' defined here}}
static_assert(__is_constructible(void));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
-// expected-note at -1 {{'void' is not constructible with provided types}} \
// expected-note at -1 {{because it is a cv void type}}
static_assert(__is_constructible(const void));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(const void)'}} \
-// expected-note at -1 {{'const void' is not constructible with provided types}} \
// expected-note at -1 {{because it is a cv void type}}
static_assert(__is_constructible(volatile void));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(volatile void)'}} \
-// expected-note at -1 {{'volatile void' is not constructible with provided types}} \
// expected-note at -1 {{because it is a cv void type}}
static_assert(__is_constructible(int ()));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(int ())'}} \
-// expected-note at -1 {{'int ()' is not constructible with provided types}} \
// expected-note at -1 {{because it is a function type}}
static_assert(__is_constructible(void (int, float)));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(void (int, float))'}} \
-// expected-note at -1 {{'void (int, float)' is not constructible with provided types}} \
// expected-note at -1 {{because it is a function type}}
}
>From cb89df9e8f7b5219987fdf98634ca5919e87e4bd Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshuraegor at gmail.com>
Date: Tue, 10 Jun 2025 08:42:00 +0000
Subject: [PATCH 3/7] Fixed problems, updated DiagnoseNonConstructibleReason
and tests
---
clang/lib/Sema/SemaTypeTraits.cpp | 10 ++--------
.../test/SemaCXX/type-traits-unsatisfied-diags.cpp | 14 +++++++++++---
2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 2b2e0c5d05891..55a5aca2d3049 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2194,7 +2194,6 @@ static void DiagnoseNonConstructibleReason(
const CXXRecordDecl *D = T->getAsCXXRecordDecl();
if (!D || D->isInvalidDecl() || !D->hasDefinition())
return;
- SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
llvm::BumpPtrAllocator OpaqueExprAllocator;
SmallVector<Expr *, 2> ArgExprs;
@@ -2211,19 +2210,14 @@ static void DiagnoseNonConstructibleReason(
EnterExpressionEvaluationContext Unevaluated(
SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
- Sema::SFINAETrap SFINAE(SemaRef, /*ForValidityCheck=*/true);
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);
- if (Init.Diagnose(SemaRef, To, InitKind, ArgExprs)) {
- auto ArgsRange = SourceRange(ArgExprs.front()->getBeginLoc(),
- ArgExprs.back()->getEndLoc());
-
- SemaRef.Diag(Loc, diag::err_ovl_no_viable_function_in_init) << T;
- }
+ Init.Diagnose(SemaRef, To, InitKind, ArgExprs);
+ SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
}
static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index 17a9fb61ce80f..ab47a6659b7ab 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -293,18 +293,26 @@ static_assert(__is_trivially_copyable(S12));
namespace constructible {
-struct S1 { // #c-S1
- S1(int);
+struct S1 { // #c-S1
+ S1(int); // #cc-S1
};
static_assert(__is_constructible(S1, char*));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, char *)'}} \
+// expected-error at -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);
+ S2(int, float, double); // #cc-S2
};
static_assert(__is_constructible(S2, float));
// expected-error at -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 at -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(void));
>From 172cee83d9dc1686075308a8acf794fc88ed4f25 Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshuraegor at gmail.com>
Date: Wed, 11 Jun 2025 20:43:54 +0000
Subject: [PATCH 4/7] Fixed tests
---
clang/test/CXX/drs/cwg18xx.cpp | 3 ++-
...overload-resolution-deferred-templates.cpp | 19 ++++++++++++++-----
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 5b4551ba0143b..c5aaa9889f232 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 { // #Baz
int a = 0;
};
static_assert(__is_constructible(Baz), "");
// since-cxx11-error at -1 {{static assertion failed due to requirement '__is_constructible(cwg1890::ex2::Bar::Baz)'}}
+ // since-cxx11-note@#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 at -1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}}
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}} \
+// expected-error at -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 at -1{{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \
+// expected-error at -1 {{no matching constructor for initialization of 'Movable'}} \
// expected-note at -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 {
>From bd3cfca0f6d3cb02f686ae0aee12b6101f518030 Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshuraegor at gmail.com>
Date: Thu, 12 Jun 2025 12:33:35 +0000
Subject: [PATCH 5/7] Removed incomplete type check. Added check for incomplete
array type for T. Updated tests.
---
.../include/clang/Basic/DiagnosticSemaKinds.td | 3 ++-
clang/lib/Sema/SemaTypeTraits.cpp | 17 +++++------------
.../SemaCXX/type-traits-unsatisfied-diags.cpp | 13 +++++++++++++
3 files changed, 20 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3f32c1cfd42ce..dd14b3e945797 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1800,7 +1800,8 @@ def note_unsatisfied_trait_reason
"%UnionWithUserDeclaredSMF{is a union with a user-declared "
"%sub{select_special_member_kind}1}|"
"%FunctionType{is a function type}|"
- "%CVVoidType{is a cv void 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 701ac45a6a4c1..067b622c4e698 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -2263,27 +2263,20 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
static void DiagnoseNonConstructibleReason(
Sema &SemaRef, SourceLocation Loc,
const llvm::SmallVector<clang::QualType, 1> &Ts) {
- bool CompleteTypes = true;
for (const auto &ArgTy : Ts) {
- if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType())
- continue;
- if (ArgTy->isIncompleteType()) {
- SemaRef.Diag(Loc, diag::err_incomplete_type_used_in_type_trait_expr)
- << ArgTy;
- CompleteTypes = false;
- }
+ if (ArgTy->isVoidType())
+ SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
+ << diag::TraitNotSatisfiedReason::CVVoidType;
}
- if (!CompleteTypes)
- return;
QualType T = Ts[0];
if (T->isFunctionType())
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
<< diag::TraitNotSatisfiedReason::FunctionType;
- if (T->isVoidType())
+ if (T->isIncompleteArrayType())
SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
- << diag::TraitNotSatisfiedReason::CVVoidType;
+ << diag::TraitNotSatisfiedReason::IncompleteArrayType;
const CXXRecordDecl *D = T->getAsCXXRecordDecl();
if (!D || D->isInvalidDecl() || !D->hasDefinition())
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index 58fb6a80474f2..c66ac86de9c7b 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -490,6 +490,19 @@ static_assert(__is_constructible(S2, float));
// 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 at -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 at -1{{because it is a cv void type}} \
+// expected-error at -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 at -1 {{static assertion failed due to requirement '__is_constructible(int[])'}} \
+// expected-note at -1 {{because it is an incomplete array type}}
+
static_assert(__is_constructible(void));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
// expected-note at -1 {{because it is a cv void type}}
>From bd1e4682913ac126d714f145bc2daf131f18932e Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshuraegor at gmail.com>
Date: Thu, 12 Jun 2025 12:36:22 +0000
Subject: [PATCH 6/7] Changed Baz to cwg1890-Baz in cwg18xx.cpp
---
clang/test/CXX/drs/cwg18xx.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index c5aaa9889f232..9948075852135 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -564,12 +564,12 @@ struct A {
namespace ex2 {
#if __cplusplus >= 201103L
struct Bar {
- struct Baz { // #Baz
+ struct Baz { // #cwg1890-Baz
int a = 0;
};
static_assert(__is_constructible(Baz), "");
// since-cxx11-error at -1 {{static assertion failed due to requirement '__is_constructible(cwg1890::ex2::Bar::Baz)'}}
- // since-cxx11-note@#Baz {{'Baz' defined here}}
+ // since-cxx11-note@#cwg1890-Baz {{'Baz' defined here}}
};
#endif
} // namespace ex2
>From 124e9f1f3b7d1951b138c4b3f578d56edc8d73cd Mon Sep 17 00:00:00 2001
From: Shamshura Egor <shamshuraegor at gmail.com>
Date: Thu, 12 Jun 2025 19:58:44 +0000
Subject: [PATCH 7/7] Fixed some problems, changed behavior on void types,
updated test
---
clang/lib/Sema/SemaTypeTraits.cpp | 22 ++++++++++++++-----
.../SemaCXX/type-traits-unsatisfied-diags.cpp | 4 ++++
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index 067b622c4e698..e9ad26279f79d 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.h"
@@ -1986,9 +1987,11 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) {
if (Arg.getKind() == TemplateArgument::ArgKind::Pack) {
for (const auto &InnerArg : Arg.pack_elements())
Args.push_back(InnerArg.getAsType());
- }
- if (Arg.getKind() == TemplateArgument::ArgKind::Type)
+ } else if (Arg.getKind() == TemplateArgument::ArgKind::Type)
Args.push_back(Arg.getAsType());
+ assert((Arg.getKind() == TemplateArgument::ArgKind::Type ||
+ Arg.getKind() == TemplateArgument::ArgKind::Pack) &&
+ "Unexpected kind");
}
return {{Trait.value(), std::move(Args)}};
}
@@ -2263,12 +2266,19 @@ static void DiagnoseNonTriviallyCopyableReason(Sema &SemaRef,
static void DiagnoseNonConstructibleReason(
Sema &SemaRef, SourceLocation Loc,
const llvm::SmallVector<clang::QualType, 1> &Ts) {
- for (const auto &ArgTy : Ts) {
- if (ArgTy->isVoidType())
- SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason)
- << diag::TraitNotSatisfiedReason::CVVoidType;
+ 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)
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index c66ac86de9c7b..11903a3136039 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -507,6 +507,10 @@ static_assert(__is_constructible(void));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(void)'}} \
// expected-note at -1 {{because it is a cv void type}}
+static_assert(__is_constructible(void, void));
+// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(void, void)'}} \
+// expected-note at -1 {{because it is a cv void type}}
+
static_assert(__is_constructible(const void));
// expected-error at -1 {{static assertion failed due to requirement '__is_constructible(const void)'}} \
// expected-note at -1 {{because it is a cv void type}}
More information about the cfe-commits
mailing list