[clang] [Clang] Added explanation why a is constructible evaluated to false. (PR #143309)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 8 06:18:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Shamshura Egor (egorshamshura)
<details>
<summary>Changes</summary>
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```.
---
Full diff: https://github.com/llvm/llvm-project/pull/143309.diff
4 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+5-2)
- (modified) clang/lib/Sema/SemaTypeTraits.cpp (+33-2)
- (modified) clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp (+72)
- (modified) clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp (+44)
``````````diff
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}}
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/143309
More information about the cfe-commits
mailing list