Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -5665,28 +5665,33 @@ SourceRange()); } +static bool canUnwrapSimilarArrayTypes(const ArrayType *AT1, + const ArrayType *AT2, bool CPlusPlus20) { + // If we don't have two array types with the same constant bound nor two + // incomplete array types, we've unwrapped everything we can. + // C++20 allows the combintion of constant bound and incomplete arrays. + if (const auto *CAT1 = dyn_cast(AT1)) + if (const auto *CAT2 = dyn_cast(AT2)) + return CAT1->getSize() == CAT2->getSize(); + + return CPlusPlus20 || + (isa(AT1) && isa(AT2)); +} + /// Attempt to unwrap two types that may both be array types with the same bound /// (or both be array types of unknown bound) for the purpose of comparing the /// cv-decomposition of two types per C++ [conv.qual]. bool ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2) { bool UnwrappedAny = false; while (true) { - auto *AT1 = getAsArrayType(T1); + const auto *AT1 = getAsArrayType(T1); if (!AT1) return UnwrappedAny; - auto *AT2 = getAsArrayType(T2); + const auto *AT2 = getAsArrayType(T2); if (!AT2) return UnwrappedAny; - // If we don't have two array types with the same constant bound nor two - // incomplete array types, we've unwrapped everything we can. - if (auto *CAT1 = dyn_cast(AT1)) { - auto *CAT2 = dyn_cast(AT2); - if (!CAT2 || CAT1->getSize() != CAT2->getSize()) - return UnwrappedAny; - } else if (!isa(AT1) || - !isa(AT2)) { + if (!canUnwrapSimilarArrayTypes(AT1, AT2, getLangOpts().CPlusPlus20)) return UnwrappedAny; - } T1 = AT1->getElementType(); T2 = AT2->getElementType(); Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -5060,8 +5060,10 @@ Result.setBad(BadConversionSequence::no_conversion, From, ToType); // We need a complete type for what follows. Incomplete types can never be - // initialized from init lists. - if (!S.isCompleteType(From->getBeginLoc(), ToType)) + // initialized from init lists. In C++20 an array of unknown bound can be + // initialized form a init list. + if (!S.isCompleteType(From->getBeginLoc(), ToType) && + !S.getLangOpts().CPlusPlus20 && !isa(ToType)) return Result; // Per DR1467: Index: clang/test/SemaCXX/const-cast.cpp =================================================================== --- clang/test/SemaCXX/const-cast.cpp +++ clang/test/SemaCXX/const-cast.cpp @@ -66,9 +66,15 @@ (void) const_cast(&ar); // ok (void) const_cast(&aub); // ok // ... but the array bound must exactly match. - (void) const_cast(&ar); // expected-error {{const_cast from 'const int *(*)[100]' to 'int *(*)[]' is not allowed}} + (void) const_cast(&ar); +#if __cplusplus < 202002L // P0388 + // expected-error@-2 {{const_cast from 'const int *(*)[100]' to 'int *(*)[]' is not allowed}} +#endif (void) const_cast(&ar); // expected-error {{const_cast from 'const int *(*)[100]' to 'int *(*)[99]' is not allowed}} - (void) const_cast(&aub); // expected-error {{const_cast from 'const int *(*)[]' to 'int *(*)[100]' is not allowed}} + (void) const_cast(&aub); +#if __cplusplus < 202002L // P0388 + // expected-error@-2 {{const_cast from 'const int *(*)[]' to 'int *(*)[100]' is not allowed}} +#endif f fp1 = 0; // Function pointers. f fp2 = const_cast(fp1); // expected-error {{const_cast to 'f' (aka 'int (*)(int)'), which is not a reference, pointer-to-object, or pointer-to-data-member}} Index: clang/test/SemaCXX/overload-call.cpp =================================================================== --- clang/test/SemaCXX/overload-call.cpp +++ clang/test/SemaCXX/overload-call.cpp @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify %s // RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify -std=c++98 %s // RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify -std=c++11 %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify -std=c++14 %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify -std=c++17 %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -pedantic -verify -std=c++20 %s int* f(int) { return 0; } float* f(float) { return 0; } @@ -721,4 +724,25 @@ } } // namespace InitializerListToArray + +namespace P0338 { +void f(int(&&)[]); +void f(double(&&)[]); +void f(int(&&)[2]); + +void g() { + f({1}); +#if __cplusplus < 202002L +// expected-error@+3 {{type 'double' cannot be narrowed to 'int' in initializer list}} +// expected-note@+2 {{insert an explicit cast to silence this issue}} +#endif + f({1.0}); +#if __cplusplus < 202002L +// expected-error@+3 2 {{type 'double' cannot be narrowed to 'int' in initializer list}} +// expected-note@+2 2 {{insert an explicit cast to silence this issue}} +#endif + f({1.0, 2.0}); + f({1, 2}); +} +} // namespace P0338 #endif Index: clang/www/cxx_status.html =================================================================== --- clang/www/cxx_status.html +++ clang/www/cxx_status.html @@ -1188,7 +1188,7 @@ Permit conversions to arrays of unknown bound P0388R4 - No + Clang 12 constinit