-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][bytecode] Don't narrow() when dereferencing to array type #129524
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
It doesn't make sense to do this if the result is supposed to be an array.
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesIt doesn't make sense to do this if the result is supposed to be an array. Full diff: https://github.com/llvm/llvm-project/pull/129524.diff 2 Files Affected:
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 74f5d6ebd9ca6..aff931a1ec939 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -6028,14 +6028,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());
|
jph-13
pushed a commit
to jph-13/llvm-project
that referenced
this pull request
Mar 21, 2025
…vm#129524) It doesn't make sense to do this if the result is supposed to be an array.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
clang:frontend
Language frontend issues, e.g. anything involving "Sema"
clang
Clang issues not falling into any other category
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
It doesn't make sense to do this if the result is supposed to be an array.