diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index aa3e3322faa42..5eaae6bdd2bc6 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(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 Captures); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index a92b788366434..9107525a44f22 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 4c433f7fe9dac..282298971705b 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 9b21f428b0af7..42777194cc76d 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 421048aaff5c9..ca09b0481bcac 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 a35689d52978f..275ddcbae7393 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();