[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-19 Thread Ross Kirsling via cfe-commits


@@ -99,6 +127,14 @@ static_assert(std::is_trivially_copyable_v);
 // expected-note@-1 {{'int &' is not trivially copyable}} \
 // expected-note@-1 {{because it is a reference type}}
 
+static_assert(std::is_assignable::value);
+
+static_assert(std::is_assignable::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 
'std::{{.*}}is_assignable::value'}} \
+// expected-error@-1 {{assigning to 'int' from incompatible type 'void'}}

rkirsling wrote:

Right, at first I wondered if I needed to recapitulate all of these existing 
diagnostic messages somehow, just to ensure that it would all be `note`s 
against a single `error`. But it 
[appears](https://github.com/llvm/llvm-project/pull/144220/files#diff-9e681885bce5b9efd3dba53a469fb788e863d7d5f76c657232ea4c62a4147ab4)
 that `is_constructible` is also incurring a second `error` (via 
`InitializationSequence::Diagnose`).

https://github.com/llvm/llvm-project/pull/144836
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-19 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling edited 
https://github.com/llvm/llvm-project/pull/144836
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix typo in is_replaceable diagnostic (PR #144247)

2025-06-15 Thread Ross Kirsling via cfe-commits

rkirsling wrote:

@ojhunt Thanks! Could you hit the green button for me as well?

https://github.com/llvm/llvm-project/pull/144247
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-19 Thread Ross Kirsling via cfe-commits

rkirsling wrote:

Seems like I don't have the ability to add reviewers yet; pinging @cor3ntin and 
@AaronBallman for visibility.

https://github.com/llvm/llvm-project/pull/144836
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [libc++][Clang] Added explanation why is_constructible evaluated to false. Updated the diagnostics checks in libc++ tests. (PR #144220)

2025-06-18 Thread Ross Kirsling via cfe-commits


@@ -1767,7 +1767,8 @@ def note_unsatisfied_trait
 : Note<"%0 is not %enum_select{"
"%TriviallyRelocatable{trivially relocatable}|"
"%Replaceable{replaceable}|"
-   "%TriviallyCopyable{trivially copyable}"
+   "%TriviallyCopyable{trivially copyable}|"
+   "%Constructible{constructible with provided types}"

rkirsling wrote:

Looks like this is no longer used in the latest version of the patch?

https://github.com/llvm/llvm-project/pull/144220
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-18 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling created 
https://github.com/llvm/llvm-project/pull/144836

Part of the work for #141911.

Checking `is_assignable` boils down to checking the well-formedness of 
`declval() = declval()`; this PR recycles logic from 
EvaluateBinaryTypeTrait in order to produce the relevant diagnostics.

>From ac74e32ad2045c27c5807ba880c0285872be3f43 Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Wed, 18 Jun 2025 21:54:35 -0700
Subject: [PATCH] [Clang] Diagnose unsatisfied `std::is_assignable`.

Part of the work for #141911.

Checking `is_assignable` boils down to checking the well-formedness of 
`declval() = declval()`; this PR recycles logic from 
EvaluateBinaryTypeTrait in order to produce the relevant diagnostics.
---
 clang/lib/Sema/SemaTypeTraits.cpp | 29 
 .../type-traits-unsatisfied-diags-std.cpp | 65 +
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 71 +++
 3 files changed, 165 insertions(+)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 22c690bedc1ed..aa3208fe51271 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1949,6 +1949,7 @@ static std::optional 
StdNameToTypeTrait(StringRef Name) {
   .Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
   .Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
   .Case("is_constructible", TypeTrait::TT_IsConstructible)
+  .Case("is_assignable", TypeTrait::BTT_IsAssignable)
   .Default(std::nullopt);
 }
 
@@ -2340,6 +2341,31 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc,
+QualType T, QualType U) {
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+
+  if (T->isObjectType() || T->isFunctionType())
+T = SemaRef.Context.getRValueReferenceType(T);
+  if (U->isObjectType() || U->isFunctionType())
+U = SemaRef.Context.getRValueReferenceType(U);
+  OpaqueValueExpr LHS(Loc, T.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(T));
+  OpaqueValueExpr RHS(Loc, U.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(U));
+
+  EnterExpressionEvaluationContext Unevaluated(
+  SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII TUContext(SemaRef,
+  SemaRef.Context.getTranslationUnitDecl());
+  SemaRef.BuildBinOp(/*S=*/nullptr, Loc, BO_Assign, &LHS, &RHS);
+
+  if (!D || D->isInvalidDecl())
+return;
+
+  SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
 void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   E = E->IgnoreParenImpCasts();
   if (E->containsErrors())
@@ -2363,6 +2389,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case TT_IsConstructible:
 DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args);
 break;
+  case BTT_IsAssignable:
+DiagnoseNonAssignableReason(*this, E->getBeginLoc(), Args[0], Args[1]);
+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 a403a0450607a..23391a799282f 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags-std.cpp
@@ -28,6 +28,14 @@ struct is_constructible {
 
 template 
 constexpr bool is_constructible_v = __is_constructible(Args...);
+
+template 
+struct is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 #ifdef STD2
@@ -63,6 +71,17 @@ using is_constructible  = 
__details_is_constructible;
 
 template 
 constexpr bool is_constructible_v = __is_constructible(Args...);
+
+template 
+struct __details_is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+using is_assignable = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 
@@ -101,6 +120,15 @@ using is_constructible  = 
__details_is_constructible;
 
 template 
 constexpr bool is_constructible_v = is_constructible::value;
+
+template 
+struct __details_is_assignable : bool_constant<__is_assignable(T, U)> {};
+
+template 
+using is_assignable  = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = is_assignable::value;
 #endif
 
 }
@@ -137,6 +165,15 @@ static_assert(std::is_constructible_v);
 // expected-error@-1 {{static assertion failed due to requirement 
'std::is_constructible_v'}} \
 // expected-note@-1 {{because it is a cv void type}}
 
+static_assert(std::is_assignable::value);
+
+static_assert(std::is_assignable::value);
+// expected-error-re@-1 {{static assertion failed due to require

[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-18 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling updated 
https://github.com/llvm/llvm-project/pull/144836

>From 580750339643b627552a1c726909dd5d12f3c9af Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Wed, 18 Jun 2025 21:54:35 -0700
Subject: [PATCH] [Clang] Diagnose unsatisfied `std::is_assignable`.

Part of the work for #141911.

Checking `is_assignable` boils down to checking the well-formedness of 
`declval() = declval()`; this PR recycles logic from 
EvaluateBinaryTypeTrait in order to produce the relevant diagnostics.
---
 clang/lib/Sema/SemaTypeTraits.cpp | 29 
 .../type-traits-unsatisfied-diags-std.cpp | 64 +
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 71 +++
 3 files changed, 164 insertions(+)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 4dbb2450857e0..1d4b6b7f34775 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1956,6 +1956,7 @@ static std::optional 
StdNameToTypeTrait(StringRef Name) {
 TypeTrait::UTT_IsCppTriviallyRelocatable)
   .Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
   .Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
+  .Case("is_assignable", TypeTrait::BTT_IsAssignable)
   .Default(std::nullopt);
 }
 
@@ -2285,6 +2286,31 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc,
+QualType T, QualType U) {
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+
+  if (T->isObjectType() || T->isFunctionType())
+T = SemaRef.Context.getRValueReferenceType(T);
+  if (U->isObjectType() || U->isFunctionType())
+U = SemaRef.Context.getRValueReferenceType(U);
+  OpaqueValueExpr LHS(Loc, T.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(T));
+  OpaqueValueExpr RHS(Loc, U.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(U));
+
+  EnterExpressionEvaluationContext Unevaluated(
+  SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII TUContext(SemaRef,
+  SemaRef.Context.getTranslationUnitDecl());
+  SemaRef.BuildBinOp(/*S=*/nullptr, Loc, BO_Assign, &LHS, &RHS);
+
+  if (!D || D->isInvalidDecl())
+return;
+
+  SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
 void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   E = E->IgnoreParenImpCasts();
   if (E->containsErrors())
@@ -2305,6 +2331,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsTriviallyCopyable:
 DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
 break;
+  case BTT_IsAssignable:
+DiagnoseNonAssignableReason(*this, E->getBeginLoc(), Args[0], Args[1]);
+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 329b60c1d..33b92326aec21 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 
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template 
+struct is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 #ifdef STD2
@@ -44,6 +52,17 @@ using is_trivially_copyable  = 
__details_is_trivially_copyable;
 
 template 
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template 
+struct __details_is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+using is_assignable = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 
@@ -73,6 +92,15 @@ using is_trivially_copyable  = 
__details_is_trivially_copyable;
 
 template 
 constexpr bool is_trivially_copyable_v = is_trivially_copyable::value;
+
+template 
+struct __details_is_assignable : bool_constant<__is_assignable(T, U)> {};
+
+template 
+using is_assignable  = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = is_assignable::value;
 #endif
 
 }
@@ -99,6 +127,14 @@ static_assert(std::is_trivially_copyable_v);
 // expected-note@-1 {{'int &' is not trivially copyable}} \
 // expected-note@-1 {{because it is a reference type}}
 
+static_assert(std::is_assignable::value);
+
+static_assert(std::is_assignable::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 
'std::{{.*}}is_assignable::value'}} \
+// expected-error@-1 {{assigning to 'int' from incompatible type 'void'}}
+static_assert(std::is_assignable_v);
+// expected-error@-1 {{static assertion failed due to req

[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-24 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling updated 
https://github.com/llvm/llvm-project/pull/144836

>From 580750339643b627552a1c726909dd5d12f3c9af Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Wed, 18 Jun 2025 21:54:35 -0700
Subject: [PATCH 1/3] [Clang] Diagnose unsatisfied `std::is_assignable`.

Part of the work for #141911.

Checking `is_assignable` boils down to checking the well-formedness of 
`declval() = declval()`; this PR recycles logic from 
EvaluateBinaryTypeTrait in order to produce the relevant diagnostics.
---
 clang/lib/Sema/SemaTypeTraits.cpp | 29 
 .../type-traits-unsatisfied-diags-std.cpp | 64 +
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 71 +++
 3 files changed, 164 insertions(+)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 4dbb2450857e0..1d4b6b7f34775 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1956,6 +1956,7 @@ static std::optional 
StdNameToTypeTrait(StringRef Name) {
 TypeTrait::UTT_IsCppTriviallyRelocatable)
   .Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
   .Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
+  .Case("is_assignable", TypeTrait::BTT_IsAssignable)
   .Default(std::nullopt);
 }
 
@@ -2285,6 +2286,31 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc,
+QualType T, QualType U) {
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+
+  if (T->isObjectType() || T->isFunctionType())
+T = SemaRef.Context.getRValueReferenceType(T);
+  if (U->isObjectType() || U->isFunctionType())
+U = SemaRef.Context.getRValueReferenceType(U);
+  OpaqueValueExpr LHS(Loc, T.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(T));
+  OpaqueValueExpr RHS(Loc, U.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(U));
+
+  EnterExpressionEvaluationContext Unevaluated(
+  SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII TUContext(SemaRef,
+  SemaRef.Context.getTranslationUnitDecl());
+  SemaRef.BuildBinOp(/*S=*/nullptr, Loc, BO_Assign, &LHS, &RHS);
+
+  if (!D || D->isInvalidDecl())
+return;
+
+  SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
 void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   E = E->IgnoreParenImpCasts();
   if (E->containsErrors())
@@ -2305,6 +2331,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsTriviallyCopyable:
 DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
 break;
+  case BTT_IsAssignable:
+DiagnoseNonAssignableReason(*this, E->getBeginLoc(), Args[0], Args[1]);
+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 329b60c1d..33b92326aec21 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 
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template 
+struct is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 #ifdef STD2
@@ -44,6 +52,17 @@ using is_trivially_copyable  = 
__details_is_trivially_copyable;
 
 template 
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template 
+struct __details_is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+using is_assignable = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 
@@ -73,6 +92,15 @@ using is_trivially_copyable  = 
__details_is_trivially_copyable;
 
 template 
 constexpr bool is_trivially_copyable_v = is_trivially_copyable::value;
+
+template 
+struct __details_is_assignable : bool_constant<__is_assignable(T, U)> {};
+
+template 
+using is_assignable  = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = is_assignable::value;
 #endif
 
 }
@@ -99,6 +127,14 @@ static_assert(std::is_trivially_copyable_v);
 // expected-note@-1 {{'int &' is not trivially copyable}} \
 // expected-note@-1 {{because it is a reference type}}
 
+static_assert(std::is_assignable::value);
+
+static_assert(std::is_assignable::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 
'std::{{.*}}is_assignable::value'}} \
+// expected-error@-1 {{assigning to 'int' from incompatible type 'void'}}
+static_assert(std::is_assignable_v);
+// expected-error@-1 {{static assertion failed due to

[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-24 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling updated 
https://github.com/llvm/llvm-project/pull/144836

>From 580750339643b627552a1c726909dd5d12f3c9af Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Wed, 18 Jun 2025 21:54:35 -0700
Subject: [PATCH 1/2] [Clang] Diagnose unsatisfied `std::is_assignable`.

Part of the work for #141911.

Checking `is_assignable` boils down to checking the well-formedness of 
`declval() = declval()`; this PR recycles logic from 
EvaluateBinaryTypeTrait in order to produce the relevant diagnostics.
---
 clang/lib/Sema/SemaTypeTraits.cpp | 29 
 .../type-traits-unsatisfied-diags-std.cpp | 64 +
 .../SemaCXX/type-traits-unsatisfied-diags.cpp | 71 +++
 3 files changed, 164 insertions(+)

diff --git a/clang/lib/Sema/SemaTypeTraits.cpp 
b/clang/lib/Sema/SemaTypeTraits.cpp
index 4dbb2450857e0..1d4b6b7f34775 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1956,6 +1956,7 @@ static std::optional 
StdNameToTypeTrait(StringRef Name) {
 TypeTrait::UTT_IsCppTriviallyRelocatable)
   .Case("is_replaceable", TypeTrait::UTT_IsReplaceable)
   .Case("is_trivially_copyable", TypeTrait::UTT_IsTriviallyCopyable)
+  .Case("is_assignable", TypeTrait::BTT_IsAssignable)
   .Default(std::nullopt);
 }
 
@@ -2285,6 +2286,31 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc,
+QualType T, QualType U) {
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+
+  if (T->isObjectType() || T->isFunctionType())
+T = SemaRef.Context.getRValueReferenceType(T);
+  if (U->isObjectType() || U->isFunctionType())
+U = SemaRef.Context.getRValueReferenceType(U);
+  OpaqueValueExpr LHS(Loc, T.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(T));
+  OpaqueValueExpr RHS(Loc, U.getNonLValueExprType(SemaRef.Context),
+  Expr::getValueKindForType(U));
+
+  EnterExpressionEvaluationContext Unevaluated(
+  SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::ContextRAII TUContext(SemaRef,
+  SemaRef.Context.getTranslationUnitDecl());
+  SemaRef.BuildBinOp(/*S=*/nullptr, Loc, BO_Assign, &LHS, &RHS);
+
+  if (!D || D->isInvalidDecl())
+return;
+
+  SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
+}
+
 void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   E = E->IgnoreParenImpCasts();
   if (E->containsErrors())
@@ -2305,6 +2331,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) {
   case UTT_IsTriviallyCopyable:
 DiagnoseNonTriviallyCopyableReason(*this, E->getBeginLoc(), Args[0]);
 break;
+  case BTT_IsAssignable:
+DiagnoseNonAssignableReason(*this, E->getBeginLoc(), Args[0], Args[1]);
+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 329b60c1d..33b92326aec21 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 
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template 
+struct is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 #ifdef STD2
@@ -44,6 +52,17 @@ using is_trivially_copyable  = 
__details_is_trivially_copyable;
 
 template 
 constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
+
+template 
+struct __details_is_assignable {
+static constexpr bool value = __is_assignable(T, U);
+};
+
+template 
+using is_assignable = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = __is_assignable(T, U);
 #endif
 
 
@@ -73,6 +92,15 @@ using is_trivially_copyable  = 
__details_is_trivially_copyable;
 
 template 
 constexpr bool is_trivially_copyable_v = is_trivially_copyable::value;
+
+template 
+struct __details_is_assignable : bool_constant<__is_assignable(T, U)> {};
+
+template 
+using is_assignable  = __details_is_assignable;
+
+template 
+constexpr bool is_assignable_v = is_assignable::value;
 #endif
 
 }
@@ -99,6 +127,14 @@ static_assert(std::is_trivially_copyable_v);
 // expected-note@-1 {{'int &' is not trivially copyable}} \
 // expected-note@-1 {{because it is a reference type}}
 
+static_assert(std::is_assignable::value);
+
+static_assert(std::is_assignable::value);
+// expected-error-re@-1 {{static assertion failed due to requirement 
'std::{{.*}}is_assignable::value'}} \
+// expected-error@-1 {{assigning to 'int' from incompatible type 'void'}}
+static_assert(std::is_assignable_v);
+// expected-error@-1 {{static assertion failed due to

[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-24 Thread Ross Kirsling via cfe-commits


@@ -1725,14 +1725,15 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, 
TypeTrait BTT,
 
 // Build expressions that emulate the effect of declval() and
 // declval().
-if (LhsT->isObjectType() || LhsT->isFunctionType())
-  LhsT = Self.Context.getRValueReferenceType(LhsT);
-if (RhsT->isObjectType() || RhsT->isFunctionType())
-  RhsT = Self.Context.getRValueReferenceType(RhsT);
-OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context),
-Expr::getValueKindForType(LhsT));
-OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context),
-Expr::getValueKindForType(RhsT));
+auto createOpaqueExpr = [&](QualType Ty) -> OpaqueValueExpr {

rkirsling wrote:

Oh, sure. No worries!

https://github.com/llvm/llvm-project/pull/144836
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Diagnose unsatisfied `std::is_assignable`. (PR #144836)

2025-06-24 Thread Ross Kirsling via cfe-commits


@@ -2285,6 +2286,31 @@ static void DiagnoseNonTriviallyCopyableReason(Sema 
&SemaRef,
   SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D;
 }
 
+static void DiagnoseNonAssignableReason(Sema &SemaRef, SourceLocation Loc,
+QualType T, QualType U) {
+  const CXXRecordDecl *D = T->getAsCXXRecordDecl();
+
+  if (T->isObjectType() || T->isFunctionType())

rkirsling wrote:

Sounds great! Updated.

https://github.com/llvm/llvm-project/pull/144836
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix fix-it hint regression from #143460 (PR #144069)

2025-06-13 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling updated 
https://github.com/llvm/llvm-project/pull/144069

>From be121c500684e971ad696be8d53db732665d851c Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Fri, 13 Jun 2025 21:51:25 +0900
Subject: [PATCH 1/3] [Clang] Fix fix-it hint regression from #143460

`:` began displaying as `colon` in the fix-it hint for a `case` with a missing 
colon.
---
 clang/lib/Parse/ParseStmt.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 434ea68442819..c0c9bbc2e15c6 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -836,8 +836,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext 
StmtCtx,
 
   Diag(ExpectedLoc, diag::err_expected_after)
   << "'case'" << tok::colon
-  << FixItHint::CreateInsertion(ExpectedLoc,
-tok::getTokenName(tok::colon));
+  << FixItHint::CreateInsertion(ExpectedLoc, ":");
 
   ColonLoc = ExpectedLoc;
 }

>From 26f4db70221b106b286566c1434530848567e849 Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Fri, 13 Jun 2025 22:08:26 +0900
Subject: [PATCH 2/3] Update test case.

---
 clang/test/Parser/switch-recovery.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/test/Parser/switch-recovery.cpp 
b/clang/test/Parser/switch-recovery.cpp
index 40712799933c2..b84c3f0a9865e 100644
--- a/clang/test/Parser/switch-recovery.cpp
+++ b/clang/test/Parser/switch-recovery.cpp
@@ -236,6 +236,9 @@ namespace GH143216 {
 int f(int x) {
   switch (x) {
   case FOO // expected-error {{expected ':' after 'case'}}
+   // CHECK: {{^}}  case FOO
+   // CHECK: {{^}}  ^
+   // CHECK: {{^}}  :
 return 0;
   default:
 return 1;

>From 425228fcf90c068dd05620ee4c57e6075e25430a Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Sat, 14 Jun 2025 00:31:12 +0900
Subject: [PATCH 3/3] Move test to new file.

---
 clang/test/FixIt/fixit-punctuator-spelling.cpp | 10 ++
 clang/test/Parser/switch-recovery.cpp  |  3 ---
 2 files changed, 10 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/FixIt/fixit-punctuator-spelling.cpp

diff --git a/clang/test/FixIt/fixit-punctuator-spelling.cpp 
b/clang/test/FixIt/fixit-punctuator-spelling.cpp
new file mode 100644
index 0..3cba0e7b64594
--- /dev/null
+++ b/clang/test/FixIt/fixit-punctuator-spelling.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | 
FileCheck %s
+
+void f(int x) {
+  switch (x) {
+case 1 // expected-error {{expected ':' after 'case'}}
+  break;
+  }
+}
+// CHECK: fix-it:"{{.*}}":{6:11-6:11}:":"
diff --git a/clang/test/Parser/switch-recovery.cpp 
b/clang/test/Parser/switch-recovery.cpp
index b84c3f0a9865e..40712799933c2 100644
--- a/clang/test/Parser/switch-recovery.cpp
+++ b/clang/test/Parser/switch-recovery.cpp
@@ -236,9 +236,6 @@ namespace GH143216 {
 int f(int x) {
   switch (x) {
   case FOO // expected-error {{expected ':' after 'case'}}
-   // CHECK: {{^}}  case FOO
-   // CHECK: {{^}}  ^
-   // CHECK: {{^}}  :
 return 0;
   default:
 return 1;

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix fix-it hint regression from #143460 (PR #144069)

2025-06-13 Thread Ross Kirsling via cfe-commits

rkirsling wrote:

@AaronBallman Looks like this is the PR we're going with after all—could I have 
you merge it for me? Thanks! :bow:

https://github.com/llvm/llvm-project/pull/144069
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] use colon char instead of token name (PR #144068)

2025-06-13 Thread Ross Kirsling via cfe-commits

rkirsling wrote:

Ohh, you beat me by a minute. 😆 I can close #144069 then.

https://github.com/llvm/llvm-project/pull/144068
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] fix missing source location for errors in macro-expanded (PR #143460)

2025-06-13 Thread Ross Kirsling via cfe-commits


@@ -832,10 +832,13 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext 
StmtCtx,
   << "'case'" << tok::colon
   << FixItHint::CreateReplacement(ColonLoc, ":");
 } else {
-  SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
+  SourceLocation ExpectedLoc = getEndOfPreviousToken();
+
   Diag(ExpectedLoc, diag::err_expected_after)
   << "'case'" << tok::colon
-  << FixItHint::CreateInsertion(ExpectedLoc, ":");
+  << FixItHint::CreateInsertion(ExpectedLoc,
+tok::getTokenName(tok::colon));

rkirsling wrote:

Opened #144069, since it's such a quick fix.

https://github.com/llvm/llvm-project/pull/143460
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix fix-it hint regression from #143460 (PR #144069)

2025-06-13 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling created 
https://github.com/llvm/llvm-project/pull/144069

Following #143460, `:` began displaying as `colon` in the fix-it hint for a 
`case` with a missing colon, as is visible in the description of (the separate 
bug) #144052.

This PR simply reverts a line that didn't need to be changed.

>From be121c500684e971ad696be8d53db732665d851c Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Fri, 13 Jun 2025 21:51:25 +0900
Subject: [PATCH] [Clang] Fix fix-it hint regression from #143460

`:` began displaying as `colon` in the fix-it hint for a `case` with a missing 
colon.
---
 clang/lib/Parse/ParseStmt.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 434ea68442819..c0c9bbc2e15c6 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -836,8 +836,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext 
StmtCtx,
 
   Diag(ExpectedLoc, diag::err_expected_after)
   << "'case'" << tok::colon
-  << FixItHint::CreateInsertion(ExpectedLoc,
-tok::getTokenName(tok::colon));
+  << FixItHint::CreateInsertion(ExpectedLoc, ":");
 
   ColonLoc = ExpectedLoc;
 }

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix fix-it hint regression from #143460 (PR #144069)

2025-06-13 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling updated 
https://github.com/llvm/llvm-project/pull/144069

>From be121c500684e971ad696be8d53db732665d851c Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Fri, 13 Jun 2025 21:51:25 +0900
Subject: [PATCH 1/2] [Clang] Fix fix-it hint regression from #143460

`:` began displaying as `colon` in the fix-it hint for a `case` with a missing 
colon.
---
 clang/lib/Parse/ParseStmt.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 434ea68442819..c0c9bbc2e15c6 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -836,8 +836,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext 
StmtCtx,
 
   Diag(ExpectedLoc, diag::err_expected_after)
   << "'case'" << tok::colon
-  << FixItHint::CreateInsertion(ExpectedLoc,
-tok::getTokenName(tok::colon));
+  << FixItHint::CreateInsertion(ExpectedLoc, ":");
 
   ColonLoc = ExpectedLoc;
 }

>From 26f4db70221b106b286566c1434530848567e849 Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Fri, 13 Jun 2025 22:08:26 +0900
Subject: [PATCH 2/2] Update test case.

---
 clang/test/Parser/switch-recovery.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/test/Parser/switch-recovery.cpp 
b/clang/test/Parser/switch-recovery.cpp
index 40712799933c2..b84c3f0a9865e 100644
--- a/clang/test/Parser/switch-recovery.cpp
+++ b/clang/test/Parser/switch-recovery.cpp
@@ -236,6 +236,9 @@ namespace GH143216 {
 int f(int x) {
   switch (x) {
   case FOO // expected-error {{expected ':' after 'case'}}
+   // CHECK: {{^}}  case FOO
+   // CHECK: {{^}}  ^
+   // CHECK: {{^}}  :
 return 0;
   default:
 return 1;

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] use colon char instead of token name (PR #144068)

2025-06-13 Thread Ross Kirsling via cfe-commits

rkirsling wrote:

I believe I'd need somebody to hit the merge button for me regardless, so I 
think we can just merge whichever one and close the other. 😅 The two approaches 
are mostly the same, I just figured that the surrounding code was consistent in 
using a literal `":"`, while there doesn't seem to be a precedent for using 
`tok::getPunctuatorSpelling` with a constant.

Either way, sorry to cause a run-around!

https://github.com/llvm/llvm-project/pull/144068
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] use colon char instead of token name (PR #144068)

2025-06-13 Thread Ross Kirsling via cfe-commits

rkirsling wrote:

Oh oops! Thanks for the correction.

https://github.com/llvm/llvm-project/pull/144068
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] fix missing source location for errors in macro-expanded (PR #143460)

2025-06-13 Thread Ross Kirsling via cfe-commits


@@ -832,10 +832,13 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext 
StmtCtx,
   << "'case'" << tok::colon
   << FixItHint::CreateReplacement(ColonLoc, ":");
 } else {
-  SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
+  SourceLocation ExpectedLoc = getEndOfPreviousToken();
+
   Diag(ExpectedLoc, diag::err_expected_after)
   << "'case'" << tok::colon
-  << FixItHint::CreateInsertion(ExpectedLoc, ":");
+  << FixItHint::CreateInsertion(ExpectedLoc,
+tok::getTokenName(tok::colon));

rkirsling wrote:

Whoops, looks like this caused the word `colon` to be displayed instead of `:`.
https://godbolt.org/z/rjzdsKqqh

https://github.com/llvm/llvm-project/pull/143460
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] fix missing source location for errors in macro-expanded (PR #143460)

2025-06-13 Thread Ross Kirsling via cfe-commits


@@ -832,10 +832,13 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext 
StmtCtx,
   << "'case'" << tok::colon
   << FixItHint::CreateReplacement(ColonLoc, ":");
 } else {
-  SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
+  SourceLocation ExpectedLoc = getEndOfPreviousToken();
+
   Diag(ExpectedLoc, diag::err_expected_after)
   << "'case'" << tok::colon
-  << FixItHint::CreateInsertion(ExpectedLoc, ":");
+  << FixItHint::CreateInsertion(ExpectedLoc,
+tok::getTokenName(tok::colon));

rkirsling wrote:

Sure! Checking locally, it looks like this line could be safely reverted. Lemme 
know if you'd prefer me to submit the fix instead.

https://github.com/llvm/llvm-project/pull/143460
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix fix-it hint regression from #143460 (PR #144069)

2025-06-14 Thread Ross Kirsling via cfe-commits

rkirsling wrote:

(This seems to be an intermittent existing failure.)

https://github.com/llvm/llvm-project/pull/144069
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [Clang] Fix typo in is_replaceable diagnostic (PR #144247)

2025-06-14 Thread Ross Kirsling via cfe-commits

https://github.com/rkirsling created 
https://github.com/llvm/llvm-project/pull/144247

Adjustment to #143265; `because it not` should be `because it is not`.

>From 9bd2d17ddcbcdfaf4236ce4e4eadf0f5724a478e Mon Sep 17 00:00:00 2001
From: Ross Kirsling 
Date: Sat, 14 Jun 2025 21:42:47 -0700
Subject: [PATCH] [Clang] Fix typo in is_replaceable diagnostic.

Adjustment to #143265; `because it not` should be `because it is not`.
---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
 clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a2cf84d024193..c502f816512c5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1780,7 +1780,7 @@ def note_unsatisfied_trait_reason
"%HasArcLifetime{has an ARC lifetime qualifier}|"
"%VLA{is a variably-modified type}|"
"%VBase{has a virtual base %1}|"
-   "%NotScalarOrClass{not %select{a|an array of objects of}1 scalar or 
"
+   "%NotScalarOrClass{is not %select{a|an array of objects of}1 scalar 
or "
"class type}|"
"%NTRBase{has a non-trivially-relocatable base %1}|"
"%NTRField{has a non-trivially-relocatable member %1 of type %2}|"
diff --git a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp 
b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
index d0b3f294fbcab..c431c364bb1c9 100644
--- a/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
+++ b/clang/test/SemaCXX/type-traits-unsatisfied-diags.cpp
@@ -166,7 +166,7 @@ static_assert(__builtin_is_replaceable(const volatile int));
 static_assert(__builtin_is_replaceable(void()));
 // expected-error@-1 {{static assertion failed due to requirement 
'__builtin_is_replaceable(void ())}} \
 // expected-note@-1 {{'void ()' is not replaceable}} \
-// expected-note@-1 {{because it not a scalar or class type}}
+// expected-note@-1 {{because it is not a scalar or class type}}
 
 struct B {
  virtual ~B();

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits