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 <shamshurae...@gmail.com> Date: Sun, 8 Jun 2025 13:09:54 +0000 Subject: [PATCH 1/8] 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@-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 {{'void' is not constructible with provided types}} \ +// 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 {{'void' is not constructible with provided types}} \ +// 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 +158,15 @@ 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 {{'void' is not constructible with provided types}} \ + // 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 {{'void' is not constructible with provided types}} \ + // expected-note@-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@-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@-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@-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@-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@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, int, float)'}} \ +// expected-note@-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@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \ +// expected-note@-1 {{'S2' is not constructible with provided types}} \ +// expected-note@#c-S2 {{'S2' defined here}} + +static_assert(__is_constructible(void)); +// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void)'}} \ +// expected-note@-1 {{'void' is not constructible with provided types}} \ +// 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 {{'const void' is not constructible with provided types}} \ +// 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 {{'volatile void' is not constructible with provided types}} \ +// 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 {{'int ()' is not constructible with provided types}} \ +// 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 {{'void (int, float)' is not constructible with provided types}} \ +// expected-note@-1 {{because it is a function type}} +} >From ef7955642a1f3f2a45ec26277021d8c7ee671e1a Mon Sep 17 00:00:00 2001 From: Shamshura Egor <shamshurae...@gmail.com> Date: Mon, 9 Jun 2025 16:18:48 +0000 Subject: [PATCH 2/8] 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@-1 {{static assertion failed due to requirement 'std::{{.*}}is_constructible<void>::value'}} \ -// expected-note@-1 {{'void' is not constructible with provided types}} \ // 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 {{'void' is not constructible with provided types}} \ // expected-note@-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@-1 {{static assertion failed due to requirement '{{.*}}is_constructible<void>::value'}} \ - // expected-note@-1 {{'void' is not constructible with provided types}} \ // 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 {{'void' is not constructible with provided types}} \ // expected-note@-1 {{because it is a cv void type}} } @@ -231,7 +227,6 @@ void test() { // 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 {{'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@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S1, int, float)'}} \ -// expected-note@-1 {{'S1' is not constructible with provided types}} \ +static_assert(__is_constructible(S1, char*)); +// expected-error@-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@-1 {{static assertion failed due to requirement '__is_constructible(constructible::S2, float)'}} \ -// expected-note@-1 {{'S2' is not constructible with provided types}} \ // expected-note@#c-S2 {{'S2' defined here}} static_assert(__is_constructible(void)); // expected-error@-1 {{static assertion failed due to requirement '__is_constructible(void)'}} \ -// expected-note@-1 {{'void' is not constructible with provided types}} \ // 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 {{'const void' is not constructible with provided types}} \ // 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 {{'volatile void' is not constructible with provided types}} \ // 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 {{'int ()' is not constructible with provided types}} \ // 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 {{'void (int, float)' is not constructible with provided types}} \ // expected-note@-1 {{because it is a function type}} } >From cb89df9e8f7b5219987fdf98634ca5919e87e4bd Mon Sep 17 00:00:00 2001 From: Shamshura Egor <shamshurae...@gmail.com> Date: Tue, 10 Jun 2025 08:42:00 +0000 Subject: [PATCH 3/8] 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@-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); + 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(void)); >From 172cee83d9dc1686075308a8acf794fc88ed4f25 Mon Sep 17 00:00:00 2001 From: Shamshura Egor <shamshurae...@gmail.com> Date: Wed, 11 Jun 2025 20:43:54 +0000 Subject: [PATCH 4/8] 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@-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@-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 { >From bd3cfca0f6d3cb02f686ae0aee12b6101f518030 Mon Sep 17 00:00:00 2001 From: Shamshura Egor <shamshurae...@gmail.com> Date: Thu, 12 Jun 2025 12:33:35 +0000 Subject: [PATCH 5/8] 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@-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}} >From bd1e4682913ac126d714f145bc2daf131f18932e Mon Sep 17 00:00:00 2001 From: Shamshura Egor <shamshurae...@gmail.com> Date: Thu, 12 Jun 2025 12:36:22 +0000 Subject: [PATCH 6/8] 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@-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 <shamshurae...@gmail.com> Date: Thu, 12 Jun 2025 19:58:44 +0000 Subject: [PATCH 7/8] 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@-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}} >From e18073b1f26f89cb111f116db393a4a93652389e Mon Sep 17 00:00:00 2001 From: Shamshura Egor <shamshurae...@gmail.com> Date: Thu, 12 Jun 2025 20:05:41 +0000 Subject: [PATCH 8/8] Added curley brackets, changed assert to llvm_unreachable --- clang/lib/Sema/SemaTypeTraits.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index e9ad26279f79d..90e0896e19df3 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -1987,11 +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()); - } else 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"); + } else { + llvm_unreachable("Unexpected kind"); + } } return {{Trait.value(), std::move(Args)}}; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits