Author: Amirreza Ashouri Date: 2023-10-11T17:12:15+02:00 New Revision: 4313351c135cc32cdf3b3fc3e44cf57f100a96ef
URL: https://github.com/llvm/llvm-project/commit/4313351c135cc32cdf3b3fc3e44cf57f100a96ef DIFF: https://github.com/llvm/llvm-project/commit/4313351c135cc32cdf3b3fc3e44cf57f100a96ef.diff LOG: [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. Added: Modified: clang/include/clang/AST/DeclCXX.h clang/lib/AST/DeclCXX.cpp clang/lib/AST/Type.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/Sema/SemaLambda.cpp clang/test/SemaCXX/type-traits.cpp Removed: ################################################################################ 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 4c433f7fe9daca0..282298971705ba0 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2663,6 +2663,8 @@ static bool HasNonDeletedDefaultedEqualityComparison(const CXXRecordDecl *Decl) { if (Decl->isUnion()) return false; + if (Decl->isLambda()) + 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() diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index a35689d52978fcc..275ddcbae73930d 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]; @@ -3193,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(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits