Author: Timm Baeder Date: 2026-06-08T12:58:59+02:00 New Revision: 0c57db633d6ae411e42b8aa53f328a785e258653
URL: https://github.com/llvm/llvm-project/commit/0c57db633d6ae411e42b8aa53f328a785e258653 DIFF: https://github.com/llvm/llvm-project/commit/0c57db633d6ae411e42b8aa53f328a785e258653.diff LOG: [clang][bytecode] Reject GetField{,Pop} ops on non-records (#202260) Similar to what we do in GetPtrField{,Pop}. Added: clang/test/AST/ByteCode/libcxx/getfield-nonrecord.cpp Modified: clang/lib/AST/ByteCode/Interp.h Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index d2ca122d0e805..4d72204f51db9 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -1631,6 +1631,13 @@ bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) { return false; if (!CheckRange(S, OpPC, Obj, CSK_Field)) return false; + + // FIXME(postswitch): The isUnknownSizeArray() check here is only needed + // to keep an invalid sample producing the same diagnostics as the current + // interpreter. + if (!Obj.getFieldDesc()->isRecord() && !Obj.isUnknownSizeArray()) + return false; + const Pointer &Field = Obj.atField(I); if (!CheckLoad(S, OpPC, Field)) return false; @@ -1638,35 +1645,42 @@ bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) { return true; } +/// 1) Pops a pointer from the stack +/// 2) Pushes the value of the pointer's field on the stack template <PrimType Name, class T = typename PrimConv<Name>::T> -bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { - const T &Value = S.Stk.pop<T>(); - const Pointer &Obj = S.Stk.peek<Pointer>(); +bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) { + const Pointer &Obj = S.Stk.pop<Pointer>(); if (!CheckNull(S, OpPC, Obj, CSK_Field)) return false; if (!CheckRange(S, OpPC, Obj, CSK_Field)) return false; + + // FIXME(postswitch): The isUnknownSizeArray() check here is only needed + // to keep an invalid sample producing the same diagnostics as the current + // interpreter. + if (!Obj.getFieldDesc()->isRecord() && !Obj.isUnknownSizeArray()) + return false; + const Pointer &Field = Obj.atField(I); - if (!CheckStore(S, OpPC, Field)) + if (!CheckLoad(S, OpPC, Field)) return false; - Field.initialize(); - Field.deref<T>() = Value; + S.Stk.push<T>(Field.deref<T>()); return true; } -/// 1) Pops a pointer from the stack -/// 2) Pushes the value of the pointer's field on the stack template <PrimType Name, class T = typename PrimConv<Name>::T> -bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) { - const Pointer &Obj = S.Stk.pop<Pointer>(); +bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { + const T &Value = S.Stk.pop<T>(); + const Pointer &Obj = S.Stk.peek<Pointer>(); if (!CheckNull(S, OpPC, Obj, CSK_Field)) return false; if (!CheckRange(S, OpPC, Obj, CSK_Field)) return false; const Pointer &Field = Obj.atField(I); - if (!CheckLoad(S, OpPC, Field)) + if (!CheckStore(S, OpPC, Field)) return false; - S.Stk.push<T>(Field.deref<T>()); + Field.initialize(); + Field.deref<T>() = Value; return true; } diff --git a/clang/test/AST/ByteCode/libcxx/getfield-nonrecord.cpp b/clang/test/AST/ByteCode/libcxx/getfield-nonrecord.cpp new file mode 100644 index 0000000000000..e4b4463445a83 --- /dev/null +++ b/clang/test/AST/ByteCode/libcxx/getfield-nonrecord.cpp @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -std=c++2c -fexperimental-new-constant-interpreter -verify=expected,both %s -Wno-undefined-internal +// RUN: %clang_cc1 -std=c++2c -verify=ref,both %s -Wno-undefined-internal + +// both-no-diagnostics + +namespace std { +inline namespace { +template <class _Tp> constexpr _Tp &&forward(_Tp &); +template <class _Tp> constexpr __remove_reference_t(_Tp) &&move(_Tp &&); +template <decltype(sizeof(int)), class> struct tuple_element; +template <class> struct tuple_size; +template <class, class _T2> struct pair { + _T2 second; +}; +template <class _T1, class _T2> pair<_T1, _T2> make_pair(_T1, _T2); +template <class _T1, class _T2> struct tuple_size<pair<_T1, _T2>> { + static const int value = 2; +}; +template <class _T1, class _T2> struct tuple_element<0, pair<_T1, _T2>> { + using type = _T1; +}; +template <class _T1, class _T2> struct tuple_element<1, pair<_T1, _T2>> { + using type = _T2; +}; +template <int> struct __get_pair { + template <class _T1, class _T2> static _T1 &&get(pair<_T1, _T2>); +}; +template <> struct __get_pair<1> { + template <class _T1, class _T2> + static constexpr _T2 &&get(pair<_T1, _T2> &&__p) { + return std::forward(__p.second); + } +}; +template <int _Ip, class _T1, class _T2> +constexpr tuple_element<_Ip, pair<_T1, _T2>>::type &&get(pair<_T1, _T2> &&__p) { + return __get_pair<_Ip>::get(std::move(__p)); +} +namespace _Algorithm { +struct __for_each; +} +template <class> struct __single_range; +template <class...> struct __specialized_algorithm; +template <class, class> using for_each_result = int; +struct { + template <typename _Range, class _Func> + for_each_result<_Range, _Func> operator()(_Range __range, _Func __func) { + using _SpecialAlg = + __specialized_algorithm<_Algorithm::__for_each, __single_range<_Range>>; + _SpecialAlg()(__range, __func, 0); + return {}; + } +} for_each; +template <class, class, class> struct __tree; +template <class _Tp, class _Compare, class _Allocator> +struct __specialized_algorithm< + _Algorithm::__for_each, __single_range<__tree<_Tp, _Compare, _Allocator>>> { + template <class _Tree, class _Func, class _Proj> + auto operator()(_Tree, _Func __func, _Proj) { + return make_pair(0, __func); + } +}; +template <class, class, class = int, class = int> struct map { + typedef __tree<int, int, int> __base; +}; +template <class _Key, class _Tp, class _Compare, class _Allocator> +struct __specialized_algorithm< + _Algorithm::__for_each, + __single_range<map<_Key, _Tp, _Compare, _Allocator>>> { + template <class _Map, class _Func, class _Proj> + auto operator()(_Map __map, _Func __func, _Proj) { + auto [_, __func2] = __specialized_algorithm< + _Algorithm::__for_each, + __single_range<typename map<_Compare, _Allocator>::__base>>()( + __map, __func, 0); + return __func2; + } +}; +} // namespace +} // namespace std + + +template <class Converter> void test_node_container(Converter) { + std::map<int, int> c; + int invoke_count; + std::for_each(c, [&invoke_count] {}); +} +void test() { + test_node_container([] {}); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
