Author: Timm Baeder Date: 2025-07-06T18:59:24+02:00 New Revision: 9c7320e5d370be7f79ad5835f9f623ac3d30a30a
URL: https://github.com/llvm/llvm-project/commit/9c7320e5d370be7f79ad5835f9f623ac3d30a30a DIFF: https://github.com/llvm/llvm-project/commit/9c7320e5d370be7f79ad5835f9f623ac3d30a30a.diff LOG: [clang][bytecode] Fix visiting for-range loop variable (#147188) Make sure we're properly registering DecompositionDecls. Added: clang/test/AST/ByteCode/libcxx/tuple-decompose-for-range.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 5ed65f21bb2c0..d1c93e4694667 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -5545,7 +5545,6 @@ bool Compiler<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) { const Stmt *BeginStmt = S->getBeginStmt(); const Stmt *RangeStmt = S->getRangeStmt(); const Stmt *EndStmt = S->getEndStmt(); - const VarDecl *LoopVar = S->getLoopVariable(); LabelTy EndLabel = this->getLabel(); LabelTy CondLabel = this->getLabel(); @@ -5570,7 +5569,7 @@ bool Compiler<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) { if (!this->jumpFalse(EndLabel)) return false; - if (!this->visitVarDecl(LoopVar)) + if (!this->visitDeclStmt(S->getLoopVarStmt(), /*EvaluateConditionDecl=*/true)) return false; // Body. diff --git a/clang/test/AST/ByteCode/libcxx/tuple-decompose-for-range.cpp b/clang/test/AST/ByteCode/libcxx/tuple-decompose-for-range.cpp new file mode 100644 index 0000000000000..df7ef3fe5ae96 --- /dev/null +++ b/clang/test/AST/ByteCode/libcxx/tuple-decompose-for-range.cpp @@ -0,0 +1,264 @@ +// RUN: %clang_cc1 -std=c++2c -verify=expected,both %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++2c -verify=ref,both %s + +// both-no-diagnostics + +namespace std { +typedef __SIZE_TYPE__ size_t; +} +extern "C++" { +namespace std { +template <typename> struct iterator_traits; +} +} +namespace std { +template <typename _Tp, _Tp __v> struct integral_constant { + static constexpr _Tp value = __v; +}; +template <bool __v> using __bool_constant = integral_constant<bool, __v>; +using false_type = __bool_constant<false>; +template <bool, typename _Tp = void> struct enable_if { + using type = _Tp; +}; +template <bool> struct __conditional { + template <typename _Tp, typename> using type = _Tp; +}; +template <bool _Cond, typename _If, typename _Else> +using __conditional_t = + typename __conditional<_Cond>::template type<_If, _Else>; +template <typename _Tp> +struct is_empty : public __bool_constant<__is_empty(_Tp)> {}; +template <typename _Tp, typename _Up> +struct is_same : public __bool_constant<__is_same(_Tp, _Up)> {}; +template <typename _Tp> struct remove_cv { + using type = __remove_cv(_Tp); +}; +template <typename _Tp> struct tuple_size; +template <typename _Tp, typename _Up = typename remove_cv<_Tp>::type, + typename = typename enable_if<is_same<_Tp, _Up>::value>::type, + size_t = tuple_size<_Tp>::value> +using __enable_if_has_tuple_size = _Tp; +template <typename _Tp> +struct tuple_size<const __enable_if_has_tuple_size<_Tp>> + : public tuple_size<_Tp> {}; +template <size_t __i, typename _Tp> struct tuple_element; +template <size_t __i, typename _Tp> +using __tuple_element_t = typename tuple_element<__i, _Tp>::type; +template <size_t __i, typename _Tp> struct tuple_element<__i, const _Tp> { + using type = const __tuple_element_t<__i, _Tp>; +}; +template <size_t _Np, typename... _Types> struct _Nth_type { + using type = __type_pack_element<_Np, _Types...>; +}; +template <typename _Tp> struct iterator_traits<_Tp *> { + using reference = _Tp &; +}; +} // namespace std +extern "C++" { +void *operator new(std::size_t, void *__p); +} +namespace std { +template <typename _Tp, typename... _Args> +constexpr inline void _Construct(_Tp *__p, _Args &&...__args) { + ::new (__p) _Tp(__args...); +}; +} // namespace std +namespace __gnu_cxx { +template <typename _Iterator, typename _Container> class __normal_iterator { +protected: + _Iterator _M_current; + typedef std::iterator_traits<_Iterator> __traits_type; + +public: + typedef _Iterator iterator_type; + typedef typename __traits_type::reference reference; + explicit constexpr __normal_iterator(const _Iterator &__i) + : _M_current(__i) {}; + constexpr reference operator*() const { return *_M_current; } + constexpr __normal_iterator &operator++() { + ++_M_current; + return *this; + } + constexpr const _Iterator &base() const { return _M_current; } +}; +template <typename _Iterator, typename _Container> +constexpr bool +operator==(const __normal_iterator<_Iterator, _Container> &__lhs, + const __normal_iterator<_Iterator, _Container> &__rhs) { + return __lhs.base() == __rhs.base(); +} +} // namespace __gnu_cxx +namespace std { +template <typename _Tp> class __new_allocator {}; +template <typename _Tp> using __allocator_base = __new_allocator<_Tp>; +template <typename> struct allocator_traits; +template <typename _Tp> class allocator : public __allocator_base<_Tp> { +public: + typedef _Tp value_type; + constexpr _Tp *allocate(size_t __n) { + __n *= sizeof(_Tp); + return static_cast<_Tp *>(::operator new(__n)); + } + constexpr void deallocate(_Tp *__p, size_t __n) { ::operator delete(__p); } +}; +template <typename _Tp> struct allocator_traits<allocator<_Tp>> { + using allocator_type = allocator<_Tp>; + using pointer = _Tp *; + using size_type = std::size_t; + template <typename _Up> using rebind_alloc = allocator<_Up>; + static constexpr pointer allocate(allocator_type &__a, size_type __n) { + return __a.allocate(__n); + } + static constexpr void deallocate(allocator_type &__a, pointer __p, + size_type __n) { + __a.deallocate(__p, __n); + } +}; +} // namespace std +namespace __gnu_cxx { +template <typename _Alloc, typename = typename _Alloc::value_type> +struct __alloc_traits : std::allocator_traits<_Alloc> { + typedef std::allocator_traits<_Alloc> _Base_type; + template <typename _Tp> struct rebind { + typedef typename _Base_type::template rebind_alloc<_Tp> other; + }; +}; +} // namespace __gnu_cxx +namespace std { +template <typename _InputIterator, typename _ForwardIterator> +constexpr _ForwardIterator __do_uninit_copy(_InputIterator __first, + _InputIterator __last, + _ForwardIterator __result) { + _ForwardIterator __cur = __result; + for (; __first != __last; ++__first, ++__cur) + std::_Construct(&*__cur, *__first); + return __cur; +}; +template <typename _InputIterator, typename _ForwardIterator, typename _Tp> +constexpr inline _ForwardIterator +__uninitialized_copy_a(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result, allocator<_Tp> &) { + return std::__do_uninit_copy(__first, __last, __result); +} +template <typename _Tp, typename _Alloc> struct _Vector_base { + typedef + typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other + _Tp_alloc_type; + typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer pointer; + struct _Vector_impl_data { + pointer _M_start; + pointer _M_finish; + pointer _M_end_of_storage; + }; + struct _Vector_impl : public _Tp_alloc_type, public _Vector_impl_data {}; + +public: + typedef _Alloc allocator_type; + constexpr _Tp_alloc_type &_M_get_Tp_allocator() { return this->_M_impl; } + constexpr _Vector_base(const allocator_type &__a) : _M_impl(__a) {} + constexpr ~_Vector_base() { + _M_deallocate(_M_impl._M_start, + _M_impl._M_end_of_storage - _M_impl._M_start); + } + +public: + _Vector_impl _M_impl; + constexpr pointer _M_allocate(size_t __n) { + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; + return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer(); + } + constexpr void _M_deallocate(pointer __p, size_t __n) { + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; + if (__p) + _Tr::deallocate(_M_impl, __p, __n); + } + +protected: +}; +template <typename _Tp, typename _Alloc = std::allocator<_Tp>> +class vector : protected _Vector_base<_Tp, _Alloc> { + typedef _Vector_base<_Tp, _Alloc> _Base; + +public: + typedef _Tp value_type; + typedef typename _Base::pointer pointer; + typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator; + typedef size_t size_type; + typedef _Alloc allocator_type; + using _Base::_M_get_Tp_allocator; + +public: +private: +public: + constexpr vector(_Tp __l, const allocator_type &__a = allocator_type()) : _Base(__a) { + + } + constexpr iterator begin() { return iterator(this->_M_impl._M_start); } + constexpr iterator end() { return iterator(this->_M_impl._M_finish); } + +protected: + template <typename _Iterator> + constexpr void _M_range_initialize_n(_Iterator __first, _Iterator __last, + size_type __n) { + pointer __start = this->_M_impl._M_start = this->_M_allocate(((__n))); + this->_M_impl._M_end_of_storage = __start + __n; + this->_M_impl._M_finish = std::__uninitialized_copy_a( + __first, __last, __start, _M_get_Tp_allocator()); + } +}; +template <typename _Tp> struct __is_empty_non_tuple : is_empty<_Tp> {}; +template <typename _Tp> +using __empty_not_final = + __conditional_t<__is_final(_Tp), false_type, __is_empty_non_tuple<_Tp>>; +template <size_t _Idx, typename _Head, bool = __empty_not_final<_Head>::value> +struct _Head_base; +template <size_t _Idx, typename _Head> struct _Head_base<_Idx, _Head, false> { + static constexpr const _Head &_M_head(const _Head_base &__b) { + return __b._M_head_impl; + } + _Head _M_head_impl; +}; +template <size_t _Idx, typename... _Elements> struct _Tuple_impl; +template <size_t _Idx, typename _Head> +struct _Tuple_impl<_Idx, _Head> : private _Head_base<_Idx, _Head> { + typedef _Head_base<_Idx, _Head> _Base; + static constexpr const _Head &_M_head(const _Tuple_impl &__t) { + return _Base::_M_head(__t); + } + explicit constexpr _Tuple_impl(const _Head &__head) : _Base(__head) {} + +protected: +}; +template <typename... _Elements> +class tuple : public _Tuple_impl<0, _Elements...> { + using _Inherited = _Tuple_impl<0, _Elements...>; + +public: + template <typename = void> + constexpr tuple(const _Elements &...__elements) : _Inherited(__elements...) {} +}; +template <typename... _Elements> +struct tuple_size<tuple<_Elements...>> + : public integral_constant<size_t, sizeof...(_Elements)> {}; +template <size_t __i, typename... _Types> +struct tuple_element<__i, tuple<_Types...>> { + using type = typename _Nth_type<__i, _Types...>::type; +}; +template <size_t __i, typename _Head, typename... _Tail> +constexpr const _Head & +__get_helper(const _Tuple_impl<__i, _Head, _Tail...> &__t) { + return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); +}; +template <size_t __i, typename... _Elements> +constexpr const int get(const tuple<_Elements...> &&__t) { + return std::__get_helper<__i>(__t); +}; +} // namespace std +constexpr int foo() { + std::vector<std::tuple<int>> data_tuples = {{1}}; + for (const auto [id] : data_tuples) { + int a = id + 3; + } + return 1; +} +static_assert(foo() == 1); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits