Skip to content

Commit 4313351

Browse files
authored
[clang] __is_trivially_equality_comparable for types containing lambdas (#68506)
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.
1 parent 3bfc5eb commit 4313351

File tree

6 files changed

+33
-9
lines changed

6 files changed

+33
-9
lines changed

clang/include/clang/AST/DeclCXX.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,12 @@ class CXXRecordDecl : public RecordDecl {
10521052
return static_cast<LambdaCaptureDefault>(getLambdaData().CaptureDefault);
10531053
}
10541054

1055+
bool isCapturelessLambda() const {
1056+
if (!isLambda())
1057+
return false;
1058+
return getLambdaCaptureDefault() == LCD_None && capture_size() == 0;
1059+
}
1060+
10551061
/// Set the captures for this lambda closure type.
10561062
void setCaptures(ASTContext &Context, ArrayRef<LambdaCapture> Captures);
10571063

clang/lib/AST/DeclCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ bool CXXRecordDecl::lambdaIsDefaultConstructibleAndAssignable() const {
686686
// C++17 [expr.prim.lambda]p21:
687687
// The closure type associated with a lambda-expression has no default
688688
// constructor and a deleted copy assignment operator.
689-
if (getLambdaCaptureDefault() != LCD_None || capture_size() != 0)
689+
if (!isCapturelessLambda())
690690
return false;
691691
return getASTContext().getLangOpts().CPlusPlus20;
692692
}

clang/lib/AST/Type.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2663,6 +2663,8 @@ static bool
26632663
HasNonDeletedDefaultedEqualityComparison(const CXXRecordDecl *Decl) {
26642664
if (Decl->isUnion())
26652665
return false;
2666+
if (Decl->isLambda())
2667+
return Decl->isCapturelessLambda();
26662668

26672669
auto IsDefaultedOperatorEqualEqual = [&](const FunctionDecl *Function) {
26682670
return Function->getOverloadedOperator() ==

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,11 +1216,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
12161216
SkippedChecks.set(SanitizerKind::ObjectSize, true);
12171217
QualType ThisTy = MD->getThisType();
12181218

1219-
// If this is the call operator of a lambda with no capture-default, it
1219+
// If this is the call operator of a lambda with no captures, it
12201220
// may have a static invoker function, which may call this operator with
12211221
// a null 'this' pointer.
1222-
if (isLambdaCallOperator(MD) &&
1223-
MD->getParent()->getLambdaCaptureDefault() == LCD_None)
1222+
if (isLambdaCallOperator(MD) && MD->getParent()->isCapturelessLambda())
12241223
SkippedChecks.set(SanitizerKind::Null, true);
12251224

12261225
EmitTypeCheck(

clang/lib/Sema/SemaLambda.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,7 @@ void Sema::DiagnoseInvalidExplicitObjectParameterInLambda(
393393
CXXRecordDecl *RD = Method->getParent();
394394
if (Method->getType()->isDependentType())
395395
return;
396-
if (RD->getLambdaCaptureDefault() == LambdaCaptureDefault::LCD_None &&
397-
RD->capture_size() == 0)
396+
if (RD->isCapturelessLambda())
398397
return;
399398
QualType ExplicitObjectParameterType = Method->getParamDecl(0)
400399
->getType()

clang/test/SemaCXX/type-traits.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3160,11 +3160,18 @@ static_assert(!__is_trivially_equality_comparable(float), "");
31603160
static_assert(!__is_trivially_equality_comparable(double), "");
31613161
static_assert(!__is_trivially_equality_comparable(long double), "");
31623162

3163-
struct TriviallyEqualityComparableNoDefaultedComparator {
3163+
struct NonTriviallyEqualityComparableNoComparator {
31643164
int i;
31653165
int j;
31663166
};
3167-
static_assert(!__is_trivially_equality_comparable(TriviallyEqualityComparableNoDefaultedComparator), "");
3167+
static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableNoComparator), "");
3168+
3169+
struct NonTriviallyEqualityComparableNonDefaultedComparator {
3170+
int i;
3171+
int j;
3172+
bool operator==(const NonTriviallyEqualityComparableNonDefaultedComparator&);
3173+
};
3174+
static_assert(!__is_trivially_equality_comparable(NonTriviallyEqualityComparableNonDefaultedComparator), "");
31683175

31693176
#if __cplusplus >= 202002L
31703177

@@ -3177,7 +3184,7 @@ struct TriviallyEqualityComparable {
31773184

31783185
bool operator==(const TriviallyEqualityComparable&) const = default;
31793186
};
3180-
static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparable), "");
3187+
static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparable));
31813188

31823189
struct TriviallyEqualityComparableContainsArray {
31833190
int a[4];
@@ -3193,6 +3200,17 @@ struct TriviallyEqualityComparableContainsMultiDimensionArray {
31933200
};
31943201
static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableContainsMultiDimensionArray));
31953202

3203+
auto GetNonCapturingLambda() { return [](){ return 42; }; }
3204+
3205+
struct TriviallyEqualityComparableContainsLambda {
3206+
[[no_unique_address]] decltype(GetNonCapturingLambda()) l;
3207+
int i;
3208+
3209+
bool operator==(const TriviallyEqualityComparableContainsLambda&) const = default;
3210+
};
3211+
static_assert(!__is_trivially_equality_comparable(decltype(GetNonCapturingLambda()))); // padding
3212+
static_assert(__is_trivially_equality_comparable(TriviallyEqualityComparableContainsLambda));
3213+
31963214
struct TriviallyEqualityComparableNonTriviallyCopyable {
31973215
TriviallyEqualityComparableNonTriviallyCopyable(const TriviallyEqualityComparableNonTriviallyCopyable&);
31983216
~TriviallyEqualityComparableNonTriviallyCopyable();

0 commit comments

Comments
 (0)