https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/128141
... when creating the temporary variables for a MaterializeTemporaryExpr. >From c097cff3502bf0fbbbd2a1c8c791f578fd1ce507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Thu, 20 Feb 2025 20:22:15 +0100 Subject: [PATCH] [clang][bytecode] Use ExtendingDecl mechanism for primitives as well ... when creating the temporary variables for a MaterializeTemporaryExpr. --- clang/lib/AST/ByteCode/Compiler.cpp | 89 +++--- clang/lib/AST/ByteCode/Compiler.h | 2 +- .../ByteCode/libcxx/primitive-temporary.cpp | 271 ++++++++++++++++++ 3 files changed, 319 insertions(+), 43 deletions(-) create mode 100644 clang/test/AST/ByteCode/libcxx/primitive-temporary.cpp diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 503c58a67adeb..ec18f9d72b66f 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -567,8 +567,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { // Location for the SubExpr. // Since SubExpr is of complex type, visiting it results in a pointer // anyway, so we just create a temporary pointer variable. - unsigned SubExprOffset = allocateLocalPrimitive( - SubExpr, PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false); + unsigned SubExprOffset = + allocateLocalPrimitive(SubExpr, PT_Ptr, /*IsConst=*/true); if (!this->visit(SubExpr)) return false; if (!this->emitSetLocal(PT_Ptr, SubExprOffset, CE)) @@ -611,8 +611,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { const auto *VT = CE->getType()->getAs<VectorType>(); PrimType ElemT = classifyPrim(SubExpr->getType()); - unsigned ElemOffset = allocateLocalPrimitive( - SubExpr, ElemT, /*IsConst=*/true, /*IsExtended=*/false); + unsigned ElemOffset = + allocateLocalPrimitive(SubExpr, ElemT, /*IsConst=*/true); // Prepare a local variable for the scalar value. if (!this->visit(SubExpr)) @@ -1104,7 +1104,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { PrimType ResultElemT = this->classifyComplexElementType(E->getType()); unsigned ResultOffset = ~0u; if (!DiscardResult) - ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false); + ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, /*IsConst=*/true); // Save result pointer in ResultOffset if (!this->DiscardResult) { @@ -1178,14 +1178,14 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { // Evaluate LHS and save value to LHSOffset. if (LHSType->isAnyComplexType()) { - LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false); + LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true); if (!this->visit(LHS)) return false; if (!this->emitSetLocal(PT_Ptr, LHSOffset, E)) return false; } else { PrimType LHST = classifyPrim(LHSType); - LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false); + LHSOffset = this->allocateLocalPrimitive(LHS, LHST, /*IsConst=*/true); if (!this->visit(LHS)) return false; if (!this->emitSetLocal(LHST, LHSOffset, E)) @@ -1195,14 +1195,14 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) { // Same with RHS. unsigned RHSOffset; if (RHSType->isAnyComplexType()) { - RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false); + RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true); if (!this->visit(RHS)) return false; if (!this->emitSetLocal(PT_Ptr, RHSOffset, E)) return false; } else { PrimType RHST = classifyPrim(RHSType); - RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false); + RHSOffset = this->allocateLocalPrimitive(RHS, RHST, /*IsConst=*/true); if (!this->visit(RHS)) return false; if (!this->emitSetLocal(RHST, RHSOffset, E)) @@ -1342,14 +1342,16 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { PrimType ResultElemT = this->classifyVectorElementType(E->getType()); // Evaluate LHS and save value to LHSOffset. - unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false); + unsigned LHSOffset = + this->allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true); if (!this->visit(LHS)) return false; if (!this->emitSetLocal(PT_Ptr, LHSOffset, E)) return false; // Evaluate RHS and save value to RHSOffset. - unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false); + unsigned RHSOffset = + this->allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true); if (!this->visit(RHS)) return false; if (!this->emitSetLocal(PT_Ptr, RHSOffset, E)) @@ -2710,8 +2712,8 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( // For everyhing else, use local variables. if (SubExprT) { bool IsConst = SubExpr->getType().isConstQualified(); - unsigned LocalIndex = allocateLocalPrimitive(E, *SubExprT, IsConst, - /*IsExtended=*/true); + unsigned LocalIndex = + allocateLocalPrimitive(E, *SubExprT, IsConst, E->getExtendingDecl()); if (!this->visit(SubExpr)) return false; if (!this->emitSetLocal(*SubExprT, LocalIndex, E)) @@ -2781,7 +2783,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { unsigned LocalIndex; if (T) - LocalIndex = this->allocateLocalPrimitive(Init, *T, false, false); + LocalIndex = this->allocateLocalPrimitive(Init, *T, /*IsConst=*/false); else if (std::optional<unsigned> MaybeIndex = this->allocateLocal(Init)) LocalIndex = *MaybeIndex; else @@ -3337,8 +3339,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { PrimType SizeT = classifyPrim(Stripped->getType()); // Save evaluated array size to a variable. - unsigned ArrayLen = allocateLocalPrimitive( - Stripped, SizeT, /*IsConst=*/false, /*IsExtended=*/false); + unsigned ArrayLen = + allocateLocalPrimitive(Stripped, SizeT, /*IsConst=*/false); if (!this->visit(Stripped)) return false; if (!this->emitSetLocal(SizeT, ArrayLen, E)) @@ -3416,8 +3418,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) { } // Create loop variables. - unsigned Iter = allocateLocalPrimitive( - Stripped, SizeT, /*IsConst=*/false, /*IsExtended=*/false); + unsigned Iter = + allocateLocalPrimitive(Stripped, SizeT, /*IsConst=*/false); if (!this->emitConst(StaticInitElems, SizeT, E)) return false; if (!this->emitSetLocal(SizeT, Iter, E)) @@ -3668,8 +3670,8 @@ template <class Emitter> bool Compiler<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) { assert(E->getType()->isVoidPointerType()); - unsigned Offset = allocateLocalPrimitive( - E->getLabel(), PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false); + unsigned Offset = + allocateLocalPrimitive(E->getLabel(), PT_Ptr, /*IsConst=*/true); return this->emitGetLocal(PT_Ptr, Offset, E); } @@ -3684,7 +3686,8 @@ bool Compiler<Emitter>::VisitConvertVectorExpr(const ConvertVectorExpr *E) { QualType SrcType = Src->getType(); PrimType SrcElemT = classifyVectorElementType(SrcType); - unsigned SrcOffset = this->allocateLocalPrimitive(Src, PT_Ptr, true, false); + unsigned SrcOffset = + this->allocateLocalPrimitive(Src, PT_Ptr, /*IsConst=*/true); if (!this->visit(Src)) return false; if (!this->emitSetLocal(PT_Ptr, SrcOffset, E)) @@ -3727,8 +3730,8 @@ bool Compiler<Emitter>::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { // Save both input vectors to a local variable. unsigned VectorOffsets[2]; for (unsigned I = 0; I != 2; ++I) { - VectorOffsets[I] = this->allocateLocalPrimitive( - Vecs[I], PT_Ptr, /*IsConst=*/true, /*IsExtended=*/false); + VectorOffsets[I] = + this->allocateLocalPrimitive(Vecs[I], PT_Ptr, /*IsConst=*/true); if (!this->visit(Vecs[I])) return false; if (!this->emitSetLocal(PT_Ptr, VectorOffsets[I], E)) @@ -3780,8 +3783,7 @@ bool Compiler<Emitter>::VisitExtVectorElementExpr( } // Create a local variable for the base. - unsigned BaseOffset = allocateLocalPrimitive(Base, PT_Ptr, /*IsConst=*/true, - /*IsExtended=*/false); + unsigned BaseOffset = allocateLocalPrimitive(Base, PT_Ptr, /*IsConst=*/true); if (!this->visit(Base)) return false; if (!this->emitSetLocal(PT_Ptr, BaseOffset, E)) @@ -4193,9 +4195,8 @@ bool Compiler<Emitter>::emitConst(const APSInt &Value, const Expr *E) { } template <class Emitter> -unsigned Compiler<Emitter>::allocateLocalPrimitive(DeclTy &&Src, PrimType Ty, - bool IsConst, - bool IsExtended) { +unsigned Compiler<Emitter>::allocateLocalPrimitive( + DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl) { // Make sure we don't accidentally register the same decl twice. if (const auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) { @@ -4212,7 +4213,10 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(DeclTy &&Src, PrimType Ty, Scope::Local Local = this->createLocal(D); if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) Locals.insert({VD, Local}); - VarScope->add(Local, IsExtended); + if (ExtendingDecl) + VarScope->addExtended(Local, ExtendingDecl); + else + VarScope->add(Local, false); return Local.Offset; } @@ -4780,7 +4784,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { // decl as the function pointer. const Expr *Callee = E->getCallee(); CalleeOffset = - this->allocateLocalPrimitive(Callee, PT_MemberPtr, true, false); + this->allocateLocalPrimitive(Callee, PT_MemberPtr, /*IsConst=*/true); if (!this->visit(Callee)) return false; if (!this->emitSetLocal(PT_MemberPtr, *CalleeOffset, E)) @@ -4802,7 +4806,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { return this->emitKill(E); } else if (!FuncDecl) { const Expr *Callee = E->getCallee(); - CalleeOffset = this->allocateLocalPrimitive(Callee, PT_FnPtr, true, false); + CalleeOffset = + this->allocateLocalPrimitive(Callee, PT_FnPtr, /*IsConst=*/true); if (!this->visit(Callee)) return false; if (!this->emitSetLocal(PT_FnPtr, *CalleeOffset, E)) @@ -5404,7 +5409,8 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) { LabelTy EndLabel = this->getLabel(); OptLabelTy DefaultLabel = std::nullopt; - unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false); + unsigned CondVar = + this->allocateLocalPrimitive(Cond, CondT, /*IsConst=*/true); if (const auto *CondInit = S->getInit()) if (!visitStmt(CondInit)) @@ -6067,7 +6073,8 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) { // The offset of the temporary, if we created one. unsigned SubExprOffset = ~0u; auto createTemp = [=, &SubExprOffset]() -> bool { - SubExprOffset = this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false); + SubExprOffset = + this->allocateLocalPrimitive(SubExpr, PT_Ptr, /*IsConst=*/true); if (!this->visit(SubExpr)) return false; return this->emitSetLocal(PT_Ptr, SubExprOffset, E); @@ -6181,7 +6188,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) { // The offset of the temporary, if we created one. unsigned SubExprOffset = - this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false); + this->allocateLocalPrimitive(SubExpr, PT_Ptr, /*IsConst=*/true); if (!this->visit(SubExpr)) return false; if (!this->emitSetLocal(PT_Ptr, SubExprOffset, E)) @@ -6554,8 +6561,7 @@ bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS, if (LHS->getType()->isAnyComplexType()) { LHSIsComplex = true; ElemT = classifyComplexElementType(LHS->getType()); - LHSOffset = allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true, - /*IsExtended=*/false); + LHSOffset = allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true); if (!this->visit(LHS)) return false; if (!this->emitSetLocal(PT_Ptr, LHSOffset, E)) @@ -6563,7 +6569,7 @@ bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS, } else { LHSIsComplex = false; PrimType LHST = classifyPrim(LHS->getType()); - LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false); + LHSOffset = this->allocateLocalPrimitive(LHS, LHST, /*IsConst=*/true); if (!this->visit(LHS)) return false; if (!this->emitSetLocal(LHST, LHSOffset, E)) @@ -6575,8 +6581,7 @@ bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS, if (RHS->getType()->isAnyComplexType()) { RHSIsComplex = true; ElemT = classifyComplexElementType(RHS->getType()); - RHSOffset = allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true, - /*IsExtended=*/false); + RHSOffset = allocateLocalPrimitive(RHS, PT_Ptr, /*IsConst=*/true); if (!this->visit(RHS)) return false; if (!this->emitSetLocal(PT_Ptr, RHSOffset, E)) @@ -6584,7 +6589,7 @@ bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS, } else { RHSIsComplex = false; PrimType RHST = classifyPrim(RHS->getType()); - RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false); + RHSOffset = this->allocateLocalPrimitive(RHS, RHST, /*IsConst=*/true); if (!this->visit(RHS)) return false; if (!this->emitSetLocal(RHST, RHSOffset, E)) @@ -6761,8 +6766,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) { if (!this->visit(SubExpr)) return false; } else if (std::optional<PrimType> FromT = classify(SubExpr)) { - unsigned TempOffset = allocateLocalPrimitive( - SubExpr, *FromT, /*IsConst=*/true, /*IsExtended=*/false); + unsigned TempOffset = + allocateLocalPrimitive(SubExpr, *FromT, /*IsConst=*/true); if (!this->visit(SubExpr)) return false; if (!this->emitSetLocal(*FromT, TempOffset, E)) diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 0a93c46a40ef5..77fcc3d1b41ce 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -303,7 +303,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, /// Creates a local primitive value. unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst, - bool IsExtended = false); + const ValueDecl *ExtendingDecl = nullptr); /// Allocates a space storing a local given its type. std::optional<unsigned> diff --git a/clang/test/AST/ByteCode/libcxx/primitive-temporary.cpp b/clang/test/AST/ByteCode/libcxx/primitive-temporary.cpp new file mode 100644 index 0000000000000..475f7ffef4525 --- /dev/null +++ b/clang/test/AST/ByteCode/libcxx/primitive-temporary.cpp @@ -0,0 +1,271 @@ +// 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>; +} // namespace +inline namespace __1 { +template <class _Tp> +using __libcpp_remove_reference_t = __remove_reference_t(_Tp); +template <bool, class _IfRes, class> using conditional_t = _IfRes; +template <class _Tp, class _Up> +using _IsSame = _BoolConstant<__is_same(_Tp, _Up)>; +template <class _Tp> struct enable_if { + typedef _Tp type; +}; +template <bool, class _Tp = void> using __enable_if_t = _Tp; +template <class _Bp, class _Dp> +constexpr bool is_base_of_v = __is_base_of(_Bp, _Dp); +template <class _Tp> _Tp __declval(long); +template <class _Tp> decltype(__declval<_Tp>(0)) declval(); +template <class _Fp, class... _Args> +constexpr decltype(declval<_Fp>()(declval<_Args>()...)) +__invoke(_Fp __f, _Args... __args) { + return (__f)((__args)...); +} +template <class, class _Fp, class... _Args> struct __invokable_r { + template <class _XFp, class... _XArgs> + static decltype(__invoke(declval<_XFp>(), declval<_XArgs>()...)) + __try_call(int); + using _Result = decltype(__try_call<_Fp, _Args...>(0)); +}; +template <class _Func, class... _Args> +struct __invoke_result + : enable_if<typename __invokable_r<void, _Func, _Args...>::_Result> {}; +template <class _Fn, class... _Args> +using invoke_result_t = __invoke_result<_Fn, _Args...>::type; +template <class _Tp> constexpr __libcpp_remove_reference_t<_Tp> &&move(_Tp &&); +template <class _From, class _To> +constexpr bool is_convertible_v = __is_convertible(_From, _To); +template <class _From, class _To> +concept convertible_to = + is_convertible_v<_From, _To> && requires { (declval<_From>()); }; +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 <class _Tp> using __remove_cvref_t = __remove_cvref(_Tp); +template <class _Tp> using remove_cvref_t = __remove_cvref_t<_Tp>; +template <class _Xp, class _Yp> +using __cond_res = + decltype(false ? declval<_Xp (&)()>()() : declval<_Yp (&)()>()()); +template <class...> struct common_reference; +template <class... _Types> +using common_reference_t = common_reference<_Types...>::type; +template <class, class> struct __common_reference_sub_bullet3; +template <class _Tp, class _Up> +struct common_reference<_Tp, _Up> : __common_reference_sub_bullet3<_Tp, _Up> {}; +template <class _Tp, class _Up> + requires requires { typename __cond_res<_Tp, _Up>; } +struct __common_reference_sub_bullet3<_Tp, _Up> { + using type = __cond_res<_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 = + common_reference_with<__make_const_lvalue_ref<_Lhs>, + __make_const_lvalue_ref<_Rhs>> && + requires(_Lhs __lhs, _Rhs __rhs) { + { __lhs = (__rhs) }; + }; +template <class _Tp> +concept default_initializable = requires { _Tp{}; }; +template <class _Tp> constexpr bool is_object_v = __is_object(_Tp); +template <class _Dp, class _Bp> +concept derived_from = is_base_of_v<_Bp, _Dp> && is_convertible_v<_Dp *, _Bp *>; +template <class _Tp, class _Up> +concept __weakly_equality_comparable_with = requires( + __make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) { + { __u }; +}; +template <class _Fn, class... _Args> +constexpr invoke_result_t<_Fn, _Args...> invoke(_Fn __f, _Args &&...__args) { + return __invoke((__f), (__args)...); +} +template <class _Fn, class... _Args> +concept invocable = + requires(_Fn __fn, _Args... __args) { invoke((__fn), (__args)...); }; +template <class _Fn, class... _Args> +concept regular_invocable = invocable<_Fn, _Args...>; +template <template <class> class, class> +integral_constant<bool, false> __sfinae_test_impl(); +template <template <class> class _Templ, class... _Args> +using _IsValidExpansion = decltype(__sfinae_test_impl<_Templ, _Args...>()); +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 __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 _Tp> +concept __has_member_value_type = requires { typename _Tp; }; +template <class> struct indirectly_readable_traits; +template <class _Tp> +struct indirectly_readable_traits<_Tp *> : __cond_value_type<_Tp> {}; +template <__has_member_value_type _Tp> +struct indirectly_readable_traits<_Tp> + : __cond_value_type<typename _Tp::value_type> {}; +template <bool> struct _OrImpl; +template <> struct _OrImpl<true> { + template <class, class _First, class... _Rest> + using _Result = + _OrImpl<!bool() && sizeof...(_Rest)>::template _Result<_First, _Rest...>; +}; +template <> struct _OrImpl<false> { + template <class _Res> using _Result = _Res; +}; +template <class... _Args> +using _Or = + _OrImpl<sizeof...(_Args) != + 0>::template _Result<integral_constant<bool, false>, _Args...>; +template <class _Tp> +concept __dereferenceable = requires(_Tp __t) { + { __t }; +}; +template <__dereferenceable _Tp> +using iter_reference_t = decltype(*declval<_Tp>()); +struct input_iterator_tag {}; +struct forward_iterator_tag : input_iterator_tag {}; +struct bidirectional_iterator_tag : forward_iterator_tag {}; +struct __iter_concept_random_fallback { + template <class> + using _Apply = __enable_if_t<__is_primary_template<int>::value, + bidirectional_iterator_tag>; +}; +template <class _Tester> struct __test_iter_concept : _Tester {}; +struct __iter_concept_cache { + using type = _Or<__test_iter_concept<__iter_concept_random_fallback>>; +}; +template <class _Iter> +using _ITER_CONCEPT = __iter_concept_cache::type::_Apply<_Iter>; +template <class _Ip> +using iter_value_t = + conditional_t<__is_primary_template<int>::value, + indirectly_readable_traits<remove_cvref_t<_Ip>>, + int>::value_type; +namespace ranges { +struct Trans_NS___iter_move___fn { + template <class _Ip> auto operator()(_Ip __i) const -> decltype(move(*(__i))); +}; +inline namespace { +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(declval<_Tp>())); +template <class _In> +concept __indirectly_readable_impl = + requires(_In __i) { + { ranges::iter_move(__i) } -> same_as<iter_rvalue_reference_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 _Tp> struct __indirect_value_t_impl { + using type = iter_value_t<_Tp>; +}; +template <indirectly_readable _Tp> +using __indirect_value_t = __indirect_value_t_impl<_Tp>::type; +template <class _Sp, class _Ip> +concept sentinel_for = __weakly_equality_comparable_with<_Sp, _Ip>; +template <class _Ip> +concept input_iterator = requires { typename _ITER_CONCEPT<_Ip>; } && + derived_from<_ITER_CONCEPT<_Ip>, input_iterator_tag>; +template <class _Fp, class _It> +concept indirectly_unary_invocable = + invocable<_Fp, __indirect_value_t<_It>> && + invocable<_Fp, iter_reference_t<_It>> && + common_reference_with<invoke_result_t<_Fp, __indirect_value_t<_It>>, + invoke_result_t<_Fp, iter_reference_t<_It>>>; +template <class _Fp, class _It> +concept indirectly_regular_unary_invocable = + regular_invocable<_Fp, __indirect_value_t<_It>> && + regular_invocable<_Fp, iter_reference_t<_It>> && + common_reference_with<invoke_result_t<_Fp, __indirect_value_t<_It>>, + invoke_result_t<_Fp, iter_reference_t<_It>>>; +template <class _Fp, class... _Its> + requires(indirectly_readable<_Its> && ...) && + invocable<_Fp, iter_reference_t<_Its>...> +using indirect_result_t = invoke_result_t<_Fp, iter_reference_t<_Its>...>; +template <class _It, class _Proj> struct __projected_impl { + struct __type { + using value_type = remove_cvref_t<indirect_result_t<_Proj, _It>>; + indirect_result_t<_Proj, _It> operator*(); + }; +}; +template <indirectly_readable _It, + indirectly_regular_unary_invocable<_It> _Proj> +using projected = __projected_impl<_It, _Proj>::__type; +namespace ranges { +template <class, class> using for_each_result = int; + +struct Z {}; +constexpr Z zomg() { + return {}; +} +constexpr Z zomg2(Z z) { + return {}; +} + +struct __for_each { + + template <input_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj, + indirectly_unary_invocable<projected<_Iter, _Proj>> _Func> + constexpr for_each_result<_Iter, _Func> + operator()(_Iter __first, _Sent __last, _Func __func, _Proj __proj) const { + + for (; __first != __last; ++__first) + invoke(__func, invoke(__proj, *__first)); + return {}; + } + +}; +inline namespace { +auto for_each = __for_each{}; +} +} // namespace ranges +} // namespace __1 +} // namespace std + + + +struct T {}; +struct Proj { + constexpr void *operator()(T) { return nullptr; } +}; +struct UnaryVoid { + constexpr void operator()(void *) {} +}; + +constexpr bool all_the_algorithms() { + T a[2]; + T *last = a + 2; + std::ranges::for_each(a, last, UnaryVoid(), Proj()); + return true; +} +static_assert(all_the_algorithms()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits