[clang] [clang] __is_trivially_equality_comparable for types containing lambdas (PR #68506)
Amirreza Ashouri via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 11 04:54:24 PDT 2023
https://github.com/AMP999 updated https://github.com/llvm/llvm-project/pull/68506
>From fdbeba9c94ddb13ee53a761d9e1a95b044f2c20a Mon Sep 17 00:00:00 2001
From: Amirreza Ashouri <ar.ashouri999 at gmail.com>
Date: Sat, 7 Oct 2023 19:02:34 +0330
Subject: [PATCH 1/3] [clang] Rename some misleading names (Non-functional)
These names could be misleading; should we change them to
`NonTriviallyComparable` instead?
---
clang/test/SemaCXX/type-traits.cpp | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index a35689d52978fcc..a1315f1966a6dd4 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -3160,11 +3160,18 @@ static_assert(!__is_trivially_equality_comparable(float), "");
static_assert(!__is_trivially_equality_comparable(double), "");
static_assert(!__is_trivially_equality_comparable(long double), "");
-struct TriviallyEqualityComparableNoDefaultedComparator {
+struct NonTriviallyEqualityComparableNoComparator {
int i;
int j;
};
-static_assert(!__is_trivially_equality_comparable(TriviallyEqualityComparableNoDefaultedComparator), "");
+static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableNoComparator), "");
+
+struct NonTriviallyEqualityComparableNonDefaultedComparator {
+ int i;
+ int j;
+ bool operator==(const NonTriviallyEqualityComparableNonDefaultedComparator&);
+};
+static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableNonDefaultedComparator), "");
#if __cplusplus >= 202002L
@@ -3177,7 +3184,7 @@ struct TriviallyEqualityComparable {
bool operator==(const TriviallyEqualityComparable&) const = default;
};
-static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparable), "");
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparable));
struct TriviallyEqualityComparableContainsArray {
int a[4];
>From 5820c4e478c035a65512994f354df081266467dc Mon Sep 17 00:00:00 2001
From: Amirreza Ashouri <ar.ashouri999 at gmail.com>
Date: Sun, 8 Oct 2023 18:00:51 +0330
Subject: [PATCH 2/3] [clang] __is_trivially_equality_comparable for types
containing lambdas
Lambdas (closure types) are trivially equality-comparable iff they are
non-capturing, because non-capturing lambdas are convertible to function
pointers: if `(lam1 == lam2)` compiles, then `lam1` and `lam2` must have
the same type, and be always-equal, and be empty.
---
clang/lib/AST/Type.cpp | 3 +++
clang/test/SemaCXX/type-traits.cpp | 11 +++++++++++
2 files changed, 14 insertions(+)
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 4c433f7fe9daca0..23f856c715a5e13 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2663,6 +2663,9 @@ static bool
HasNonDeletedDefaultedEqualityComparison(const CXXRecordDecl *Decl) {
if (Decl->isUnion())
return false;
+ if (Decl->isLambda())
+ return Decl->captures().empty() &&
+ (Decl->getLambdaCaptureDefault() == LCD_None);
auto IsDefaultedOperatorEqualEqual = [&](const FunctionDecl *Function) {
return Function->getOverloadedOperator() ==
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index a1315f1966a6dd4..275ddcbae73930d 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -3200,6 +3200,17 @@ struct TriviallyEqualityComparableContainsMultiDimensionArray {
};
static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableContainsMultiDimensionArray));
+auto GetNonCapturingLambda() { return [](){ return 42; }; }
+
+struct TriviallyEqualityComparableContainsLambda {
+ [[no_unique_address]] decltype(GetNonCapturingLambda()) l;
+ int i;
+
+ bool operator==(const TriviallyEqualityComparableContainsLambda&) const = default;
+};
+static_assert(!__is_trivially_equality_comparable(decltype(GetNonCapturingLambda()))); // padding
+static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableContainsLambda));
+
struct TriviallyEqualityComparableNonTriviallyCopyable {
TriviallyEqualityComparableNonTriviallyCopyable(const TriviallyEqualityComparableNonTriviallyCopyable&);
~TriviallyEqualityComparableNonTriviallyCopyable();
>From edd82edc6dd1ca1a143b4e667d5e4a30d8e7a1d4 Mon Sep 17 00:00:00 2001
From: Arthur O'Dwyer <arthur.j.odwyer at gmail.com>
Date: Tue, 10 Oct 2023 10:03:17 -0400
Subject: [PATCH 3/3] [clang] Factor out isCapturelessLambda
This changes the behavior of the call-site in "CodeGenFunction.cpp",
I think for the better. But I couldn't figure out how to test that
codepath.
---
clang/include/clang/AST/DeclCXX.h | 6 ++++++
clang/lib/AST/DeclCXX.cpp | 2 +-
clang/lib/AST/Type.cpp | 3 +--
clang/lib/CodeGen/CodeGenFunction.cpp | 5 ++---
clang/lib/Sema/SemaLambda.cpp | 3 +--
5 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index aa3e3322faa42e3..5eaae6bdd2bc63e 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1052,6 +1052,12 @@ class CXXRecordDecl : public RecordDecl {
return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault);
}
+ bool isCapturelessLambda() const {
+ if (!isLambda())
+ return false;
+ return getLambdaCaptureDefault() == LCD_None && capture_size() == 0;
+ }
+
/// Set the captures for this lambda closure type.
void setCaptures(ASTContext &Context, ArrayRef<LambdaCapture> Captures);
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index a92b788366434ce..9107525a44f22c2 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -686,7 +686,7 @@ bool CXXRecordDecl::lambdaIsDefaultConstructibleAndAssignable() const {
// C++17 [expr.prim.lambda]p21:
// The closure type associated with a lambda-expression has no default
// constructor and a deleted copy assignment operator.
- if (getLambdaCaptureDefault() != LCD_None || capture_size() != 0)
+ if (!isCapturelessLambda())
return false;
return getASTContext().getLangOpts().CPlusPlus20;
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 23f856c715a5e13..282298971705ba0 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2664,8 +2664,7 @@ HasNonDeletedDefaultedEqualityComparison(const CXXRecordDecl *Decl) {
if (Decl->isUnion())
return false;
if (Decl->isLambda())
- return Decl->captures().empty() &&
- (Decl->getLambdaCaptureDefault() == LCD_None);
+ return Decl->isCapturelessLambda();
auto IsDefaultedOperatorEqualEqual = [&](const FunctionDecl *Function) {
return Function->getOverloadedOperator() ==
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 9b21f428b0af7f5..42777194cc76dc0 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1216,11 +1216,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
SkippedChecks.set(SanitizerKind::ObjectSize, true);
QualType ThisTy = MD->getThisType();
- // If this is the call operator of a lambda with no capture-default, it
+ // If this is the call operator of a lambda with no captures, it
// may have a static invoker function, which may call this operator with
// a null 'this' pointer.
- if (isLambdaCallOperator(MD) &&
- MD->getParent()->getLambdaCaptureDefault() == LCD_None)
+ if (isLambdaCallOperator(MD) && MD->getParent()->isCapturelessLambda())
SkippedChecks.set(SanitizerKind::Null, true);
EmitTypeCheck(
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 421048aaff5c90c..ca09b0481bcac76 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -393,8 +393,7 @@ void Sema::DiagnoseInvalidExplicitObjectParameterInLambda(
CXXRecordDecl *RD = Method->getParent();
if (Method->getType()->isDependentType())
return;
- if (RD->getLambdaCaptureDefault() == LambdaCaptureDefault::LCD_None &&
- RD->capture_size() == 0)
+ if (RD->isCapturelessLambda())
return;
QualType ExplicitObjectParameterType = Method->getParamDecl(0)
->getType()
More information about the cfe-commits
mailing list