diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 843a01f57c39f..afb10d4340599 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -570,6 +570,8 @@ Bug Fixes in This Version an array via an element-at-a-time copy loop (#GH192026) - Fixed an issue where certain designated initializers would be rejected for constexpr variables. (#GH193373) - Fixed a crash when ``#embed`` is used with C++ modules (#GH195350) +- Fixed mishandling of cv-qualified array types in ``__reference_constructs_from_temporary`` and + ``__reference_converts_from_temporary`` builtins. (#GH198580) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 96a398aa21dad..cda3d8dba08e2 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3679,13 +3679,15 @@ QualType QualType::getNonLValueExprType(const ASTContext &Context) const { if (const auto *RefType = getTypePtr()->getAs()) return RefType->getPointeeType(); - // C++0x [basic.lval]: - // Class prvalues can have cv-qualified types; non-class prvalues always - // have cv-unqualified types. + // C++26 [expr.type]p2 (see also CWG1261): + // If a prvalue initially has the type "cv T", where T is a cv-unqualified + // non-class, non-array type, the type of the expression is adjusted to T + // prior to any further analysis. // // See also C99 6.3.2.1p2. if (!Context.getLangOpts().CPlusPlus || - (!getTypePtr()->isDependentType() && !getTypePtr()->isRecordType())) + (!getTypePtr()->isDependentType() && !getTypePtr()->isRecordType() && + !getTypePtr()->isArrayType())) return getUnqualifiedType(); return *this; diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 8decb1f61395e..3b2fe8a78f37e 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -3310,6 +3310,44 @@ void reference_constructs_from_temporary_checks() { // For scalar types, cv-qualifications are dropped first for prvalues. static_assert(__reference_constructs_from_temporary(int&&, const int)); static_assert(__reference_constructs_from_temporary(int&&, volatile int)); + // For array types, cv-qualifications are *kept* for prvalues. + // Uses with type aliases need to be verified, see https://llvm.org/PR198580. + static_assert(!__reference_constructs_from_temporary(const int(&)[10], volatile int[10])); + static_assert(!__reference_constructs_from_temporary(const IntAr&, volatile int[10])); + static_assert(!__reference_constructs_from_temporary(const int(&)[10], volatile IntAr)); + static_assert(!__reference_constructs_from_temporary(const IntAr&, volatile IntAr)); + static_assert(!__reference_constructs_from_temporary(int(&&)[10], volatile int[10])); + static_assert(!__reference_constructs_from_temporary(IntAr&&, volatile int[10])); + static_assert(!__reference_constructs_from_temporary(int(&&)[10], volatile IntAr)); + static_assert(!__reference_constructs_from_temporary(IntAr&&, volatile IntAr)); + static_assert(__reference_constructs_from_temporary(volatile int(&&)[10], volatile int[10])); + static_assert(__reference_constructs_from_temporary(volatile IntAr&&, volatile int[10])); + static_assert(__reference_constructs_from_temporary(volatile int(&&)[10], volatile IntAr)); + static_assert(__reference_constructs_from_temporary(volatile IntAr&&, volatile IntAr)); + static_assert(!__reference_constructs_from_temporary(int*&&, volatile int[10])); + static_assert(!__reference_constructs_from_temporary(int*&&, volatile IntAr)); + static_assert(!__reference_constructs_from_temporary(int* const&, volatile int[10])); + static_assert(!__reference_constructs_from_temporary(int* const&, volatile IntAr)); + static_assert(__reference_constructs_from_temporary(volatile int*&&, volatile int[10])); + static_assert(__reference_constructs_from_temporary(volatile int*&&, volatile IntAr)); + static_assert(!__reference_constructs_from_temporary(const Empty(&)[10], volatile Empty[10])); + static_assert(!__reference_constructs_from_temporary(const EmptyAr&, volatile Empty[10])); + static_assert(!__reference_constructs_from_temporary(const Empty(&)[10], volatile Empty)); + static_assert(!__reference_constructs_from_temporary(const EmptyAr&, volatile Empty)); + static_assert(!__reference_constructs_from_temporary(Empty(&&)[10], volatile Empty[10])); + static_assert(!__reference_constructs_from_temporary(EmptyAr&&, volatile int[10])); + static_assert(!__reference_constructs_from_temporary(Empty(&&)[10], volatile EmptyAr)); + static_assert(!__reference_constructs_from_temporary(EmptyAr&&, volatile EmptyAr)); + static_assert(__reference_constructs_from_temporary(volatile Empty(&&)[10], volatile Empty[10])); + static_assert(__reference_constructs_from_temporary(volatile EmptyAr&&, volatile Empty[10])); + static_assert(__reference_constructs_from_temporary(volatile Empty(&&)[10], volatile EmptyAr)); + static_assert(__reference_constructs_from_temporary(volatile EmptyAr&&, volatile EmptyAr)); + static_assert(!__reference_constructs_from_temporary(Empty*&&, volatile Empty[10])); + static_assert(!__reference_constructs_from_temporary(Empty*&&, volatile EmptyAr)); + static_assert(!__reference_constructs_from_temporary(Empty* const&, volatile Empty[10])); + static_assert(!__reference_constructs_from_temporary(Empty* const&, volatile EmptyAr)); + static_assert(__reference_constructs_from_temporary(volatile Empty*&&, volatile Empty[10])); + static_assert(__reference_constructs_from_temporary(volatile Empty*&&, volatile EmptyAr)); // Additional checks static_assert(__reference_constructs_from_temporary(POD const&, Derives)); @@ -3377,6 +3415,44 @@ void reference_converts_from_temporary_checks() { // For scalar types, cv-qualifications are dropped first for prvalues. static_assert(__reference_converts_from_temporary(int&&, const int)); static_assert(__reference_converts_from_temporary(int&&, volatile int)); + // For array types, cv-qualifications are *kept* for prvalues. + // Uses with type aliases need to be verified, see https://llvm.org/PR198580. + static_assert(!__reference_converts_from_temporary(const int(&)[10], volatile int[10])); + static_assert(!__reference_converts_from_temporary(const IntAr&, volatile int[10])); + static_assert(!__reference_converts_from_temporary(const int(&)[10], volatile IntAr)); + static_assert(!__reference_converts_from_temporary(const IntAr&, volatile IntAr)); + static_assert(!__reference_converts_from_temporary(int(&&)[10], volatile int[10])); + static_assert(!__reference_converts_from_temporary(IntAr&&, volatile int[10])); + static_assert(!__reference_converts_from_temporary(int(&&)[10], volatile IntAr)); + static_assert(!__reference_converts_from_temporary(IntAr&&, volatile IntAr)); + static_assert(__reference_converts_from_temporary(volatile int(&&)[10], volatile int[10])); + static_assert(__reference_converts_from_temporary(volatile IntAr&&, volatile int[10])); + static_assert(__reference_converts_from_temporary(volatile int(&&)[10], volatile IntAr)); + static_assert(__reference_converts_from_temporary(volatile IntAr&&, volatile IntAr)); + static_assert(!__reference_converts_from_temporary(int*&&, volatile int[10])); + static_assert(!__reference_converts_from_temporary(int*&&, volatile IntAr)); + static_assert(!__reference_converts_from_temporary(int* const&, volatile int[10])); + static_assert(!__reference_converts_from_temporary(int* const&, volatile IntAr)); + static_assert(__reference_converts_from_temporary(volatile int*&&, volatile int[10])); + static_assert(__reference_converts_from_temporary(volatile int*&&, volatile IntAr)); + static_assert(!__reference_converts_from_temporary(const Empty(&)[10], volatile Empty[10])); + static_assert(!__reference_converts_from_temporary(const EmptyAr&, volatile Empty[10])); + static_assert(!__reference_converts_from_temporary(const Empty(&)[10], volatile Empty)); + static_assert(!__reference_converts_from_temporary(const EmptyAr&, volatile Empty)); + static_assert(!__reference_converts_from_temporary(Empty(&&)[10], volatile Empty[10])); + static_assert(!__reference_converts_from_temporary(EmptyAr&&, volatile int[10])); + static_assert(!__reference_converts_from_temporary(Empty(&&)[10], volatile EmptyAr)); + static_assert(!__reference_converts_from_temporary(EmptyAr&&, volatile EmptyAr)); + static_assert(__reference_converts_from_temporary(volatile Empty(&&)[10], volatile Empty[10])); + static_assert(__reference_converts_from_temporary(volatile EmptyAr&&, volatile Empty[10])); + static_assert(__reference_converts_from_temporary(volatile Empty(&&)[10], volatile EmptyAr)); + static_assert(__reference_converts_from_temporary(volatile EmptyAr&&, volatile EmptyAr)); + static_assert(!__reference_converts_from_temporary(Empty*&&, volatile Empty[10])); + static_assert(!__reference_converts_from_temporary(Empty*&&, volatile EmptyAr)); + static_assert(!__reference_converts_from_temporary(Empty* const&, volatile Empty[10])); + static_assert(!__reference_converts_from_temporary(Empty* const&, volatile EmptyAr)); + static_assert(__reference_converts_from_temporary(volatile Empty*&&, volatile Empty[10])); + static_assert(__reference_converts_from_temporary(volatile Empty*&&, volatile EmptyAr)); // Additional checks static_assert(__reference_converts_from_temporary(POD const&, Derives)); diff --git a/clang/test/SemaHLSL/Language/InitIncompleteArrays.hlsl b/clang/test/SemaHLSL/Language/InitIncompleteArrays.hlsl index 5558575afb28d..fff5363b2337f 100644 --- a/clang/test/SemaHLSL/Language/InitIncompleteArrays.hlsl +++ b/clang/test/SemaHLSL/Language/InitIncompleteArrays.hlsl @@ -14,7 +14,7 @@ struct is_same { template struct remove_addrspace { - using type = __decltype((T)0); + using type = __typeof_unqual__(T); }; template