ayzhao created this revision. ayzhao added a reviewer: ilya-biryukov. Herald added a project: All. ayzhao requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Previously, we would only attempt to perform a parenthesized aggregate initialization if constructor initialization failed for only the default constructor, default copy constructor, and default move constructor. The original intent of this logic was to reject initializing objects that have failed resolving a user-defined constructor. However, this check is redundant because we check for isAggregate() before attempting to perform a parenthesized aggregate initialization, and classes that have user-defined or user-declared constructors are not aggregates. Furthermore, this check is too restrictive - the following valid examples fail: - Aggregate class with user-defined destructor - fails because default move constructors are not generated for classes with user-defined destructors (https://github.com/llvm/llvm-project/issues/54040#issuecomment-1356926048) - Concept-guarded conversion operator on an aggregate's member: (https://github.com/llvm/llvm-project/issues/54040#issuecomment-1356931745) The solution therefore is to remove this logic; existing tests still pass, and the previously failing examples now compile. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D140327 Files: clang/lib/Sema/SemaInit.cpp clang/test/CodeGen/paren-list-agg-init.cpp Index: clang/test/CodeGen/paren-list-agg-init.cpp =================================================================== --- clang/test/CodeGen/paren-list-agg-init.cpp +++ clang/test/CodeGen/paren-list-agg-init.cpp @@ -1,9 +1,25 @@ // RUN: %clang_cc1 -std=c++20 %s -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s +template <typename T> +struct IsChar { + constexpr operator bool() const { return false; } +}; + +template<> +struct IsChar<char> { + constexpr operator bool() const { return true; } +}; + +template <typename T> +concept SameAsChar = (bool)IsInt<T>(); + // CHECK-DAG: [[STRUCT_A:%.*]] = type { i8, double } struct A { char i; double j; + + template <SameAsChar T> + operator T() const { return i; }; }; // CHECK-DAG: [[STRUCT_B:%.*]] = type { [[STRUCT_A]], i32 } @@ -29,6 +45,7 @@ struct E { int a; const char* fn = __builtin_FUNCTION(); + ~E() {}; }; // CHECK-DAG: [[STRUCT_F:%.*]] = type { i8 } Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -5930,25 +5930,6 @@ return false; } -static bool onlyHasDefaultedCtors(OverloadCandidateSet &OCS) { - if (OCS.size() != 3) - return false; - - bool HasDefaultCtor = false, HasCopyCtor = false, HasMoveCtor = false; - for (const auto &Candidate : OCS) { - if (auto *Ctor = dyn_cast_or_null<CXXConstructorDecl>(Candidate.Function); - Ctor != nullptr && Ctor->isDefaulted()) { - if (Ctor->isDefaultConstructor()) - HasDefaultCtor = true; - else if (Ctor->isCopyConstructor()) - HasCopyCtor = true; - else if (Ctor->isMoveConstructor()) - HasMoveCtor = true; - } - } - return HasDefaultCtor && HasCopyCtor && HasMoveCtor; -} - void InitializationSequence::InitializeFrom(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -6196,8 +6177,7 @@ if (const auto *RD = dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl()); S.getLangOpts().CPlusPlus20 && RD && RD->isAggregate() && Failed() && - getFailureKind() == FK_ConstructorOverloadFailed && - onlyHasDefaultedCtors(getFailedCandidateSet())) { + getFailureKind() == FK_ConstructorOverloadFailed) { // C++20 [dcl.init] 17.6.2.2: // - Otherwise, if no constructor is viable, the destination type is // an
Index: clang/test/CodeGen/paren-list-agg-init.cpp =================================================================== --- clang/test/CodeGen/paren-list-agg-init.cpp +++ clang/test/CodeGen/paren-list-agg-init.cpp @@ -1,9 +1,25 @@ // RUN: %clang_cc1 -std=c++20 %s -emit-llvm -triple x86_64-unknown-linux-gnu -o - | FileCheck %s +template <typename T> +struct IsChar { + constexpr operator bool() const { return false; } +}; + +template<> +struct IsChar<char> { + constexpr operator bool() const { return true; } +}; + +template <typename T> +concept SameAsChar = (bool)IsInt<T>(); + // CHECK-DAG: [[STRUCT_A:%.*]] = type { i8, double } struct A { char i; double j; + + template <SameAsChar T> + operator T() const { return i; }; }; // CHECK-DAG: [[STRUCT_B:%.*]] = type { [[STRUCT_A]], i32 } @@ -29,6 +45,7 @@ struct E { int a; const char* fn = __builtin_FUNCTION(); + ~E() {}; }; // CHECK-DAG: [[STRUCT_F:%.*]] = type { i8 } Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -5930,25 +5930,6 @@ return false; } -static bool onlyHasDefaultedCtors(OverloadCandidateSet &OCS) { - if (OCS.size() != 3) - return false; - - bool HasDefaultCtor = false, HasCopyCtor = false, HasMoveCtor = false; - for (const auto &Candidate : OCS) { - if (auto *Ctor = dyn_cast_or_null<CXXConstructorDecl>(Candidate.Function); - Ctor != nullptr && Ctor->isDefaulted()) { - if (Ctor->isDefaultConstructor()) - HasDefaultCtor = true; - else if (Ctor->isCopyConstructor()) - HasCopyCtor = true; - else if (Ctor->isMoveConstructor()) - HasMoveCtor = true; - } - } - return HasDefaultCtor && HasCopyCtor && HasMoveCtor; -} - void InitializationSequence::InitializeFrom(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -6196,8 +6177,7 @@ if (const auto *RD = dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl()); S.getLangOpts().CPlusPlus20 && RD && RD->isAggregate() && Failed() && - getFailureKind() == FK_ConstructorOverloadFailed && - onlyHasDefaultedCtors(getFailedCandidateSet())) { + getFailureKind() == FK_ConstructorOverloadFailed) { // C++20 [dcl.init] 17.6.2.2: // - Otherwise, if no constructor is viable, the destination type is // an
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits