Author: Timm Baeder Date: 2025-03-03T17:14:54+01:00 New Revision: 3dafa486a6a41bacd31b3b1661fa44fa5e71520a
URL: https://github.com/llvm/llvm-project/commit/3dafa486a6a41bacd31b3b1661fa44fa5e71520a DIFF: https://github.com/llvm/llvm-project/commit/3dafa486a6a41bacd31b3b1661fa44fa5e71520a.diff LOG: [clang][bytecode] Don't narrow() when dereferencing to array type (#129524) It doesn't make sense to do this if the result is supposed to be an array. Added: clang/test/AST/ByteCode/libcxx/deref-to-array.cpp Modified: clang/lib/AST/ByteCode/Compiler.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 4cf6a48edd5e0..96f67ffca43b3 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6039,14 +6039,12 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { // We should already have a pointer when we get here. return this->delegate(SubExpr); case UO_Deref: // *x - if (DiscardResult) { - // assert(false); + if (DiscardResult) return this->discard(SubExpr); - } if (!this->visit(SubExpr)) return false; - if (classifyPrim(SubExpr) == PT_Ptr) + if (classifyPrim(SubExpr) == PT_Ptr && !E->getType()->isArrayType()) return this->emitNarrowPtr(E); return true; diff --git a/clang/test/AST/ByteCode/libcxx/deref-to-array.cpp b/clang/test/AST/ByteCode/libcxx/deref-to-array.cpp new file mode 100644 index 0000000000000..2a527ab336a0d --- /dev/null +++ b/clang/test/AST/ByteCode/libcxx/deref-to-array.cpp @@ -0,0 +1,391 @@ +// RUN: %clang_cc1 -std=c++2c -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -std=c++2c -verify=ref,both %s + +// both-no-diagnostics + +namespace std { +inline namespace { +template <class _Tp, _Tp __v> struct integral_constant { + static const _Tp value = __v; +}; +template <bool _Val> using _BoolConstant = integral_constant<bool, _Val>; +template <class _Tp> using __remove_cv_t = __remove_cv(_Tp); +template <class _Tp> using remove_cv_t = __remove_cv_t<_Tp>; +template <class _From, class _To> +constexpr bool is_convertible_v = __is_convertible(_From, _To); +template <class _Tp> _Tp __declval(long); +template <class _Tp> decltype(__declval<_Tp>(0)) declval(); +template <class _From, class _To> +concept convertible_to = is_convertible_v<_From, _To> && + requires { static_cast<_To>(declval<_From>()); }; +template <class _Tp> constexpr bool is_reference_v = __is_reference(_Tp); +template <class _Tp> +constexpr bool is_lvalue_reference_v = __is_lvalue_reference(_Tp); +template <class> +constexpr bool is_nothrow_destructible_v = + integral_constant<bool, __is_nothrow_destructible(int)>::value; +template <class _Tp> +concept destructible = is_nothrow_destructible_v<_Tp>; +template <class _Tp, class _Up> +using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>; +template <class... _Args> +constexpr bool is_constructible_v = __is_constructible(_Args...); +template <class _Tp, class... _Args> +concept constructible_from = destructible<_Tp> && is_constructible_v<_Tp>; +template <class _Tp> +concept move_constructible = + constructible_from<_Tp, _Tp> && convertible_to<_Tp, _Tp>; +template <class _Tp, class _Up> +concept __same_as_impl = _IsSame<_Tp, _Up>::value; +template <class _Tp, class _Up> +concept same_as = __same_as_impl<_Tp, _Up> && __same_as_impl<_Up, _Tp>; +template <bool> struct _IfImpl; +template <> struct _IfImpl<false> { + template <class, class _ElseRes> using _Select = _ElseRes; +}; +template <bool _Cond, class _IfRes, class _ElseRes> +using _If = _IfImpl<_Cond>::template _Select<_IfRes, _ElseRes>; +template <class _If> struct conditional { + using type = _If; +}; +template <bool, class _IfRes, class> +using conditional_t = conditional<_IfRes>::type; +template <class _Tp> +using __libcpp_remove_reference_t = __remove_reference_t(_Tp); +template <class _Tp> +using remove_reference_t = __libcpp_remove_reference_t<_Tp>; +template <class _Tp> using __decay_t = __decay(_Tp); +template <class _Tp> using __remove_cvref_t = __remove_cvref(_Tp); +template <class _Tp> using remove_cvref_t = __remove_cvref_t<_Tp>; +struct __copy_cv { + template <class _To> using __apply = _To; +}; +template <class, class _To> using __copy_cv_t = __copy_cv::__apply<_To>; +template <class _Xp, class _Yp> +using __cond_res = + decltype(false ? std::declval<_Xp (&)()>()() : std::declval<_Yp (&)()>()()); +template <class _Ap, class _Bp, class = remove_reference_t<_Ap>, + class = remove_reference_t<_Bp>> +struct __common_ref; +template <class _Ap, class _Bp, class, class> +struct __common_ref : __common_ref<_Bp, _Ap> {}; +template <class _Xp, class _Yp> +using __common_ref_t = __common_ref<_Xp, _Yp>::__type; +template <class _Xp, class _Yp> +using __cv_cond_res = + __cond_res<__copy_cv_t<_Xp, _Yp> &, __copy_cv_t<_Yp, _Xp> &>; +template <class _Ap, class _Bp, class _Xp, class _Yp> + requires requires { typename __cv_cond_res<_Xp, _Yp>; } && + is_reference_v<__cv_cond_res<_Xp, _Yp>> +struct __common_ref<_Ap, _Bp &, _Xp, _Yp> { + using __type = __cv_cond_res<_Xp, _Yp>; +}; +template <class _Tp, class _Up> +using __common_ref_D = __common_ref_t<const _Tp, _Up &>; +template <class _Ap, class _Bp, class _Xp, class _Yp> + requires requires { typename __common_ref_D<_Xp, _Yp>; } && + is_convertible_v<_Ap, __common_ref_D<_Xp, _Yp>> +struct __common_ref<_Ap &&, _Bp &, _Xp, _Yp> { + using __type = __common_ref_D<_Xp, _Yp>; +}; +template <class...> struct common_reference; +template <class... _Types> +using common_reference_t = common_reference<_Types...>::type; +template <class, class> struct __common_reference_sub_bullet1; +template <class _Tp, class _Up> +struct common_reference<_Tp, _Up> : __common_reference_sub_bullet1<_Tp, _Up> {}; +template <class _Tp, class _Up> + requires is_reference_v<_Tp> && is_reference_v<_Up> && + requires { typename __common_ref_t<_Tp, _Up>; } +struct __common_reference_sub_bullet1<_Tp, _Up> { + using type = __common_ref_t<_Tp, _Up>; +}; +template <class _Tp, class _Up> +concept common_reference_with = + same_as<common_reference_t<_Tp, _Up>, common_reference_t<_Up, _Tp>> && + convertible_to<_Tp, common_reference_t<_Tp, _Up>> && + convertible_to<_Up, common_reference_t<_Tp, _Up>>; +template <class _Tp> +using __make_const_lvalue_ref = __libcpp_remove_reference_t<_Tp> &; +template <class _Lhs, class _Rhs> +concept assignable_from = + is_lvalue_reference_v<_Lhs> && + common_reference_with<__make_const_lvalue_ref<_Lhs>, + __make_const_lvalue_ref<_Rhs>> && + requires(_Lhs __lhs, _Rhs __rhs) { + { __rhs } -> same_as<_Lhs>; + }; +template <class _Tp> constexpr __libcpp_remove_reference_t<_Tp> &&move(_Tp &&); +typedef int type; +template <bool, class = void> using __enable_if_t = type; +namespace ranges { +inline namespace { +auto swap = int{}; +} +} // namespace ranges +template <class _Tp> constexpr bool is_object_v = __is_object(_Tp); +template <class _Tp> +concept movable = is_object_v<_Tp> && move_constructible<_Tp> && + assignable_from<_Tp &, _Tp>; +template <decltype(sizeof(int)), class> struct tuple_element; +template <class...> class tuple; +template <template <class> class _Templ, class... _Args, + class = _Templ<_Args...>> +integral_constant<bool, true> __sfinae_test_impl(int); +template <template <class> class, class> +integral_constant<bool, false> __sfinae_test_impl(...); +template <template <class> class _Templ, class... _Args> +using _IsValidExpansion = + decltype(std::__sfinae_test_impl<_Templ, _Args...>(0)); +template <class _Tp> +using __test_for_primary_template = + __enable_if_t<_IsSame<_Tp, typename _Tp::__primary_template>::value>; +template <class _Tp> +using __is_primary_template = + _IsValidExpansion<__test_for_primary_template, _Tp>; +template <class> struct iterator_traits; +template <class> struct __cond_value_type; +template <class _Tp> + requires is_object_v<_Tp> +struct __cond_value_type<_Tp> { + using value_type = remove_cv_t<_Tp>; +}; +template <class> struct indirectly_readable_traits; +template <class _Tp> +struct indirectly_readable_traits<_Tp *> : __cond_value_type<_Tp> {}; +template <bool> struct _OrImpl; +template <> struct _OrImpl<true> { + template <class, class _First, class... _Rest> + using _Result = _OrImpl<!(_First::value) && + sizeof...(_Rest)>::template _Result<_First, _Rest...>; +}; +template <> struct _OrImpl<false> { + template <class _Res, class...> using _Result = _Res; +}; +template <class... _Args> +using _Or = + _OrImpl<sizeof...(_Args) != + 0>::template _Result<integral_constant<bool, false>, _Args...>; +template <class _Tp> using __with_reference = _Tp; +template <class _Tp> +concept __can_reference = requires { typename __with_reference<_Tp>; }; +template <class _Tp> +concept __dereferenceable = requires(_Tp __t) { + { __t }; +}; +template <__dereferenceable _Tp> +using iter_reference_t = decltype(*std::declval<_Tp>()); +struct input_iterator_tag {}; +struct contiguous_iterator_tag : input_iterator_tag {}; +template <class> struct __iter_traits_cache { + using type = _If<__is_primary_template<iterator_traits<int>>::value, int, + iterator_traits<int>>; +}; +template <class _Iter> using _ITER_TRAITS = __iter_traits_cache<_Iter>::type; +struct __iter_concept_concept_test { + template <class _Iter> using _Apply = _ITER_TRAITS<_Iter>::iterator_concept; +}; +template <class, class _Tester> +struct __test_iter_concept : _IsValidExpansion<_Tester::template _Apply, int>, + _Tester {}; +template <class _Iter> struct __iter_concept_cache { + using type = + _Or<__test_iter_concept<_Iter, __iter_concept_concept_test>, + __test_iter_concept<_Iter, int>, __test_iter_concept<_Iter, int>>; +}; +template <class _Iter> +using _ITER_CONCEPT = __iter_concept_cache<_Iter>::type::template _Apply<_Iter>; +template <class _Tp> + requires is_object_v<_Tp> +struct iterator_traits<_Tp> { + typedef contiguous_iterator_tag iterator_concept; +}; +template <class _Ip> +using iter_value_t = conditional_t< + __is_primary_template<iterator_traits<remove_cvref_t<_Ip>>>::value, + indirectly_readable_traits<remove_cvref_t<_Ip>>, + iterator_traits<remove_cvref_t<_Ip>>>::value_type; +template <class _Tp> _Tp *addressof(_Tp &); +template <class _Bp, class _Dp> +constexpr bool is_base_of_v = __is_base_of(_Bp, _Dp); +template <class _Dp, class _Bp> +concept derived_from = is_base_of_v<_Bp, _Dp> && is_convertible_v<_Dp *, _Bp *>; +namespace ranges { +struct Trans_NS___iter_move___fn { + template <class _Ip> + auto operator()(_Ip __i) -> decltype(std::move(*__i)); +}; +auto iter_move = Trans_NS___iter_move___fn{}; +} // namespace ranges +template <__dereferenceable _Tp> + requires requires { + { ranges::iter_move }; + } +using iter_rvalue_reference_t = + decltype(ranges::iter_move(std::declval<_Tp>())); +template <class _In> +concept __indirectly_readable_impl = + requires { typename iter_value_t<_In>; } && + common_reference_with<iter_reference_t<_In>, iter_value_t<_In> &> && + common_reference_with<iter_reference_t<_In>, + iter_rvalue_reference_t<_In>> && + common_reference_with<iter_rvalue_reference_t<_In>, iter_value_t<_In> &>; +template <class _In> +concept indirectly_readable = __indirectly_readable_impl<remove_cvref_t<_In>>; +template <class _Ip> +concept weakly_incrementable = + !same_as<_Ip, bool> && movable<_Ip> && requires(_Ip __i) { __i; }; +template <class _Ip> +concept input_or_output_iterator = requires(_Ip __i) { + { __i }; +} && weakly_incrementable<_Ip>; +template <class _Ip> +concept input_iterator = + input_or_output_iterator<_Ip> && indirectly_readable<_Ip> && requires { + typename _ITER_CONCEPT<_Ip>; + } && derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>; +namespace ranges { +struct __fn { + template <class _Tp, decltype(sizeof(int)) _Np> + constexpr auto operator()(_Tp (&__t)[_Np]) const + { + return __t; + } + template <class _Tp> constexpr auto operator()(_Tp __t) const { + return static_cast<std::__decay_t<decltype((__t.begin()))>>(__t.begin()); + } +}; +inline namespace { +auto begin = __fn{}; +} +template <class _Tp> +using iterator_t = decltype(ranges::begin(std::declval<_Tp &>())); +inline namespace { +auto end = int{}; +} +template <class _Derived> +class view_interface; +template <class _Op, class _Yp> + requires is_convertible_v<_Op, view_interface<_Yp>> +void __is_derived_from_view_interface(); +template <class _Tp> +bool enable_view = derived_from<_Tp, int> || + requires { ranges::__is_derived_from_view_interface; }; +template <class> +concept range = requires { ranges::end; }; +template <class _Tp> +concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>; +template <class _Tp> +concept view = range<_Tp> && movable<_Tp> && enable_view<_Tp>; +template <class _Tp> +concept viewable_range = + range<_Tp> && + ((view<remove_cvref_t<_Tp>> && constructible_from<remove_cvref_t<_Tp>>) || + (!view<remove_cvref_t<_Tp>> && (is_lvalue_reference_v<_Tp>))); +} // namespace ranges +template <decltype(sizeof(int))...> struct __tuple_indices; +template <class _IdxType, _IdxType... _Values> struct __integer_sequence { + template <decltype(sizeof(int)) _Sp> + using __to_tuple_indices = __tuple_indices<(_Values)...>; +}; +template <decltype(sizeof(int)) _Ep, decltype(sizeof(int)) _Sp> +using __make_indices_imp = + __make_integer_seq<__integer_sequence, decltype(sizeof(int)), + _Sp>::template __to_tuple_indices<_Sp>; +template <int _Ep, decltype(sizeof(int)) _Sp = 0> struct __make_tuple_indices { + typedef __make_indices_imp<_Ep, _Sp> type; +}; +template <class...> struct __tuple_types; +namespace ranges { +template <class _Derived> +class view_interface {}; +} // namespace ranges +template <decltype(sizeof(int)) _Ip, class... _Types> +struct tuple_element<_Ip, __tuple_types<_Types...>> { + using type = __type_pack_element<_Ip, _Types...>; +}; +template <decltype(sizeof(int)) _Ip, class... _Tp> +struct tuple_element<_Ip, tuple<_Tp...>> { + using type = tuple_element<_Ip, __tuple_types<_Tp...>>::type; +}; + +template <class... _Tp> struct tuple { + int __value_; + constexpr int get() { return __value_; } +}; +template <int _Ip, class... _Tp> constexpr void get(tuple<_Tp...> __t) { + __t.get(); +} +namespace ranges { +template <class _Tp> +struct __range_adaptor_closure {}; +template <range _Range> + requires is_object_v<_Range> +struct ref_view : view_interface<ref_view<_Range>> { + _Range *__range_; + + template <class _Tp> + constexpr ref_view(_Tp &&__t) + : __range_(std::addressof(static_cast<_Range &>(__t))) {} + constexpr iterator_t<_Range> begin() { return ranges::begin(*__range_); } +}; +template <class _Range> ref_view(_Range &) -> ref_view<_Range>; +} // namespace ranges +namespace ranges::views { +struct __fn : __range_adaptor_closure<__fn> { + template <class _Tp> auto operator()(_Tp &&__t) const { + return ranges::ref_view{__t}; + } +}; +inline namespace { +auto all = __fn{}; +} +template <ranges::viewable_range _Range> +using all_t = decltype(views::all(std::declval<_Range>())); +} // namespace ranges::views +namespace ranges { +template <input_range _View, decltype(sizeof(int)) _Np> +struct elements_view : view_interface<elements_view<_View, _Np>> { + class __iterator; + + constexpr elements_view(_View __base) : __base_(std::move(__base)) {} + constexpr auto begin() const { return __iterator(ranges::begin(__base_)); } + + _View __base_ = _View(); +}; +template <input_range _View, decltype(sizeof(int)) _Np> +struct elements_view<_View, _Np>::__iterator { + iterator_t<_View> __current_; + + constexpr void operator*() { + auto a = *__current_; + } +}; +namespace views { +namespace __elements { +template <int _Np> struct __fn : __range_adaptor_closure<__fn<_Np>> { + template <class _Range> + constexpr auto operator()(_Range &&__range) const + -> decltype(elements_view<all_t<_Range>, _Np>(__range)) { + return elements_view<all_t<_Range>, _Np>(__range); + } +}; +} // namespace __elements +inline namespace { +template <decltype(sizeof(int)) _Np> auto elements = __elements::__fn<_Np>{}; +} +} // namespace views +} // namespace ranges +} // namespace +} // namespace std +constexpr bool test() { + std::tuple<short, long> ts[]{{}}; + + + auto ev = std::ranges::views::elements<1>(ts); + auto it = ev.begin(); + + *it; + return true; +} +static_assert(test()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits