diff --git a/clang/lib/AST/ExprConstantMeta.cpp b/clang/lib/AST/ExprConstantMeta.cpp index cdf7e384598f..d5ec49144990 100644 --- a/clang/lib/AST/ExprConstantMeta.cpp +++ b/clang/lib/AST/ExprConstantMeta.cpp @@ -3098,13 +3098,17 @@ bool extract(APValue &Result, ASTContext &C, MetaActions &Meta, Range.getBegin(), ResultTy, VK_LValue, Decl, nullptr); } else if (auto *ArrTy = dyn_cast(Decl->getType())) { - QualType PtrTy = C.getPointerType(ArrTy->getElementType()); + QualType Elt = ArrTy->getElementType(); + if (auto *VD = dyn_cast(Decl)) { + if (VD->isConstexpr()) { + Elt.addConst(); + } + } ReturnsLValue = true; - if (RawResultTy.getCanonicalType().getTypePtr() != - PtrTy.getCanonicalType().getTypePtr()) + if (!RawResultTy->isPointerType() || !RawResultTy->getPointeeType().isAtLeastAsQualifiedAs(Elt, C)) return Diagnoser(Range.getBegin(), diag::metafn_extract_type_mismatch) - << 1 << PtrTy << 1 << ResultTy << Range; + << 1 << C.getPointerType(Elt) << 1 << ResultTy << Range; NestedNameSpecifierLocBuilder NNSLocBuilder; if (auto *ParentClsDecl = dyn_cast_or_null( diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 181e2772a8b4..646167a1428c 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -1010,7 +1010,7 @@ public: consteval auto is_accessible(info r, access_context ctx) -> bool { // Note: The accessibility of an enumerator may be looked up in a class - // for which it's not a member, since that enumerator could be + // for which it's not a member, since that enumerator could be if (!is_class_member(r) && !is_base(r) && !is_enumerator(r)) return true; @@ -1402,8 +1402,8 @@ consteval auto is_user_declared(info r) -> bool { } // Returns a reflection of the value held by the provided argument. -template - requires (!is_reference_v && +template + requires (!is_reference_v && __metafunction(detail::__metafn_is_structural_type, ^^T)) consteval auto reflect_constant(const T &r) -> info { return __metafunction(detail::__metafn_reflect_result, ^^T, @@ -2320,44 +2320,36 @@ consteval auto has_complete_definition(info r) -> bool { return __metafunction(detail::__metafn_has_complete_definition, r); } -_LIBCPP_END_NAMESPACE_REFLECTION_V2 - -_LIBCPP_BEGIN_NAMESPACE_STD - namespace __define_static { template inline constexpr ValTy FixedArray[sizeof...(Vals)] = {Vals...}; -template -inline constexpr span StaticSpan(S, size(S)); - -template -consteval span impl(const span &in) { - if (in.size() == 0) - return {}; - - vector Args = {^^ValTy}; - for (const auto &V : in) - Args.push_back(meta::reflect_constant(V)); - - return meta::extract>( - meta::substitute(^^StaticSpan, { meta::substitute(^^FixedArray, Args) })); -} } // namespace __define_static +template + requires (is_constructible_v, + ranges::range_reference_t>) +consteval auto reflect_constant_array(R &&elems) -> info { + using ValTy = ranges::range_value_t; + vector Args = {^^ValTy}; + for (const auto &V : elems) + Args.push_back(reflect_constant(V)); + return substitute(^^__define_static::FixedArray, Args); +} + +_LIBCPP_END_NAMESPACE_REFLECTION_V2 + +_LIBCPP_BEGIN_NAMESPACE_STD + template requires (is_constructible_v, ranges::range_reference_t>) consteval auto define_static_array(R &&elems) -> span> { using ValTy = ranges::range_value_t; - using ImplTy = span(*)(const span &); - auto impl = meta::extract(meta::substitute(^^__define_static::impl, - {^^ValTy})); - - vector vals(from_range, elems); - return impl(vals); + meta::info array = meta::reflect_constant_array(elems); + return span(extract(array), meta::extent(type_of(array))); } // Returns a static string having the provided contents. diff --git a/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp b/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp index 5bf5c4e64d6c..17647ab1a340 100644 --- a/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp +++ b/libcxx/test/std/experimental/reflection/static-arrays.pass.cpp @@ -41,7 +41,7 @@ struct Cls { }; constexpr auto objs = std::define_static_array(std::vector{1, 3, 5}); static_assert(objs.size() == 3); -static_assert(objs[0].k == 5 && objs[1].k == 7 && objs[2].k == 9); +static_assert(objs[0].k == 4 && objs[1].k == 6 && objs[2].k == 8); constexpr auto infos = std::define_static_array( nonstatic_data_members_of(^^Cls, diff --git a/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp b/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp index cc8bef63d545..a5c7f19d495c 100644 --- a/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp +++ b/libcxx/test/std/experimental/reflection/to-and-from-values.pass.cpp @@ -211,8 +211,11 @@ namespace extract_ref_semantics { // ==================== namespace extract_array_as_ptr { -constexpr int arr[] = {1, 2, 3}; -static_assert(extract(^^arr)[2] == 3); +constexpr int a[] = {1, 2, 3}; +static_assert(extract(^^a)[2] == 3); + +constexpr int b[3] = {1, 2, 3}; +static_assert(extract(^^b)[2] == 3); } // namespace extract_array_as_ptr @@ -331,7 +334,7 @@ static_assert([:rvfirst:].first == 1); namespace reflect_constant_callable { template -constexpr auto reflectValueCallable = +constexpr auto reflectValueCallable = requires { std::meta::reflect_constant(std::declval()); }; enum class E {};