mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
Add std::meta::source_location_of (std::meta::annotations_of (...)[...]) support.
Annotations on concepts clearly still don't work properly and if I put the static_asserts into qux in annotations3.C, I'm getting ICEs.
This commit is contained in:
committed by
Marek Polacek
parent
5058e9b05c
commit
8f0eea15c4
@@ -715,9 +715,14 @@ attribute_takes_identifier_p (const_tree attr_id)
|
||||
{
|
||||
const struct attribute_spec *spec = lookup_attribute_spec (attr_id);
|
||||
if (spec == NULL)
|
||||
/* Unknown attribute that we'll end up ignoring, return true so we
|
||||
don't complain about an identifier argument. */
|
||||
return true;
|
||||
{
|
||||
/* Unknown attribute that we'll end up ignoring, return true so we
|
||||
don't complain about an identifier argument. Except C++
|
||||
annotations. */
|
||||
if (c_dialect_cxx () && id_equal (attr_id, "annotation "))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
else if (!strcmp ("mode", spec->name)
|
||||
|| !strcmp ("format", spec->name)
|
||||
|| !strcmp ("cleanup", spec->name)
|
||||
|
||||
@@ -1472,6 +1472,11 @@ is_late_template_attribute (tree attr, tree decl)
|
||||
= lookup_attribute_spec (TREE_PURPOSE (attr));
|
||||
tree arg;
|
||||
|
||||
/* Handle all annotations as late, so that they aren't incorrectly
|
||||
reordered if some have dependent expressions and others don't. */
|
||||
if (is_attribute_p ("annotation ", name))
|
||||
return true;
|
||||
|
||||
if (!spec)
|
||||
/* Unknown attribute. */
|
||||
return false;
|
||||
@@ -1494,11 +1499,6 @@ is_late_template_attribute (tree attr, tree decl)
|
||||
if (is_attribute_p ("tls_model", name))
|
||||
return true;
|
||||
|
||||
/* Handle all annotations as late, so that they aren't incorrectly
|
||||
reordered if some have dependent expressions and others don't. */
|
||||
if (is_attribute_p ("annotation ", name))
|
||||
return true;
|
||||
|
||||
/* #pragma omp declare simd attribute needs to be always deferred. */
|
||||
if (flag_openmp
|
||||
&& is_attribute_p ("omp declare simd", name))
|
||||
@@ -1755,6 +1755,10 @@ cp_check_const_attributes (tree attributes)
|
||||
if (cxx_contract_attribute_p (attr))
|
||||
continue;
|
||||
|
||||
/* Annotation arguments are handled in handle_annotation_attribute. */
|
||||
if (is_attribute_p ("annotation ", get_attribute_name (attr)))
|
||||
continue;
|
||||
|
||||
tree arg;
|
||||
/* As we implement alignas using gnu::aligned attribute and
|
||||
alignas argument is a constant expression, force manifestly
|
||||
|
||||
@@ -33735,15 +33735,22 @@ cp_parser_annotation_list (cp_parser *parser)
|
||||
/*strict_p=*/true);
|
||||
if (annotation == error_mark_node)
|
||||
break;
|
||||
auto suppression
|
||||
= make_temp_override (suppress_location_wrappers, 0);
|
||||
annotation = maybe_wrap_with_location (annotation, loc);
|
||||
annotation = build_tree_list (NULL_TREE, annotation);
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
|
||||
{
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
annotation = make_pack_expansion (annotation);
|
||||
if (annotation == error_mark_node)
|
||||
break;
|
||||
}
|
||||
attributes = tree_cons (build_tree_list (internal_identifier,
|
||||
annotation_identifier),
|
||||
build_tree_list (NULL_TREE, annotation),
|
||||
attributes);
|
||||
annotation, attributes);
|
||||
if (processing_template_decl)
|
||||
ATTR_IS_DEPENDENT (attributes) = 1;
|
||||
}
|
||||
else if (token->type == CPP_NAME
|
||||
|| token->type == CPP_KEYWORD
|
||||
|
||||
@@ -1041,76 +1041,6 @@ maybe_init_meta_operators (location_t loc)
|
||||
}
|
||||
}
|
||||
|
||||
/* Process std::meta::source_location_of.
|
||||
Returns: If r represents a value, a type other than a class type or an
|
||||
enumeration type, the global namespace, or a data member description,
|
||||
then source_location{}. Otherwise, an implementation-defined
|
||||
source_location value. */
|
||||
|
||||
static tree
|
||||
eval_source_location_of (location_t loc, tree r, reflect_kind kind,
|
||||
tree std_source_location)
|
||||
{
|
||||
if (!NON_UNION_CLASS_TYPE_P (std_source_location))
|
||||
{
|
||||
error_at (loc, "%qT is not a class type", std_source_location);
|
||||
return error_mark_node;
|
||||
}
|
||||
location_t rloc = UNKNOWN_LOCATION;
|
||||
if (kind == REFLECT_BASE)
|
||||
{
|
||||
/* We don't track location_t of the base specifiers, so at least
|
||||
for now use location_t of the base parent (i.e. the derived
|
||||
class). */
|
||||
tree c = r;
|
||||
while (BINFO_INHERITANCE_CHAIN (c))
|
||||
c = BINFO_INHERITANCE_CHAIN (c);
|
||||
r = BINFO_TYPE (c);
|
||||
}
|
||||
if (OVERLOAD_TYPE_P (r) || (TYPE_P (r) && typedef_variant_p (r)))
|
||||
rloc = DECL_SOURCE_LOCATION (TYPE_NAME (r));
|
||||
else if (DECL_P (r) && r != global_namespace)
|
||||
rloc = DECL_SOURCE_LOCATION (r);
|
||||
tree decl = NULL_TREE, field = NULL_TREE;
|
||||
if (rloc != UNKNOWN_LOCATION)
|
||||
{
|
||||
/* Make sure __builtin_source_location (which depends on
|
||||
std::source_location::__impl) will work without errors. */
|
||||
tree name = get_identifier ("__impl");
|
||||
decl = lookup_qualified_name (std_source_location, name);
|
||||
if (TREE_CODE (decl) != TYPE_DECL)
|
||||
decl = NULL_TREE;
|
||||
else
|
||||
{
|
||||
name = get_identifier ("__builtin_source_location");
|
||||
decl = lookup_qualified_name (global_namespace, name);
|
||||
if (TREE_CODE (decl) != FUNCTION_DECL
|
||||
|| !fndecl_built_in_p (decl, BUILT_IN_FRONTEND)
|
||||
|| DECL_FE_FUNCTION_CODE (decl) != CP_BUILT_IN_SOURCE_LOCATION
|
||||
|| !require_deduced_type (decl, tf_warning_or_error))
|
||||
decl = NULL_TREE;
|
||||
}
|
||||
}
|
||||
if (decl)
|
||||
{
|
||||
field = TYPE_FIELDS (std_source_location);
|
||||
field = next_aggregate_field (field);
|
||||
/* Make sure std::source_location has exactly a single non-static
|
||||
data member (_M_impl in libstdc++, __ptr_ in libc++) with pointer
|
||||
type. Return {._M_impl = &*.Lsrc_locN}. */
|
||||
if (field != NULL_TREE
|
||||
&& POINTER_TYPE_P (TREE_TYPE (field))
|
||||
&& !next_aggregate_field (DECL_CHAIN (field)))
|
||||
{
|
||||
tree call = build_call_nary (TREE_TYPE (TREE_TYPE (decl)), decl, 0);
|
||||
SET_EXPR_LOCATION (call, rloc);
|
||||
call = fold_builtin_source_location (call);
|
||||
return build_constructor_single (std_source_location, field, call);
|
||||
}
|
||||
}
|
||||
return build_constructor (std_source_location, nullptr);
|
||||
}
|
||||
|
||||
/* Process std::meta::is_variable.
|
||||
Returns: true if r represents a variable. Otherwise, false. */
|
||||
|
||||
@@ -2591,6 +2521,78 @@ eval_type_of (location_t loc, const constexpr_ctx *ctx, tree r,
|
||||
return get_reflection_raw (loc, type_of (r, kind));
|
||||
}
|
||||
|
||||
/* Process std::meta::source_location_of.
|
||||
Returns: If r represents a value, a type other than a class type or an
|
||||
enumeration type, the global namespace, or a data member description,
|
||||
then source_location{}. Otherwise, an implementation-defined
|
||||
source_location value. */
|
||||
|
||||
static tree
|
||||
eval_source_location_of (location_t loc, tree r, reflect_kind kind,
|
||||
tree std_source_location)
|
||||
{
|
||||
if (!NON_UNION_CLASS_TYPE_P (std_source_location))
|
||||
{
|
||||
error_at (loc, "%qT is not a class type", std_source_location);
|
||||
return error_mark_node;
|
||||
}
|
||||
location_t rloc = UNKNOWN_LOCATION;
|
||||
if (kind == REFLECT_BASE)
|
||||
{
|
||||
/* We don't track location_t of the base specifiers, so at least
|
||||
for now use location_t of the base parent (i.e. the derived
|
||||
class). */
|
||||
tree c = r;
|
||||
while (BINFO_INHERITANCE_CHAIN (c))
|
||||
c = BINFO_INHERITANCE_CHAIN (c);
|
||||
r = BINFO_TYPE (c);
|
||||
}
|
||||
if (OVERLOAD_TYPE_P (r) || (TYPE_P (r) && typedef_variant_p (r)))
|
||||
rloc = DECL_SOURCE_LOCATION (TYPE_NAME (r));
|
||||
else if (DECL_P (r) && r != global_namespace)
|
||||
rloc = DECL_SOURCE_LOCATION (r);
|
||||
else if (eval_is_annotation (r) == boolean_true_node)
|
||||
rloc = EXPR_LOCATION (TREE_VALUE (TREE_VALUE (r)));
|
||||
tree decl = NULL_TREE, field = NULL_TREE;
|
||||
if (rloc != UNKNOWN_LOCATION)
|
||||
{
|
||||
/* Make sure __builtin_source_location (which depends on
|
||||
std::source_location::__impl) will work without errors. */
|
||||
tree name = get_identifier ("__impl");
|
||||
decl = lookup_qualified_name (std_source_location, name);
|
||||
if (TREE_CODE (decl) != TYPE_DECL)
|
||||
decl = NULL_TREE;
|
||||
else
|
||||
{
|
||||
name = get_identifier ("__builtin_source_location");
|
||||
decl = lookup_qualified_name (global_namespace, name);
|
||||
if (TREE_CODE (decl) != FUNCTION_DECL
|
||||
|| !fndecl_built_in_p (decl, BUILT_IN_FRONTEND)
|
||||
|| DECL_FE_FUNCTION_CODE (decl) != CP_BUILT_IN_SOURCE_LOCATION
|
||||
|| !require_deduced_type (decl, tf_warning_or_error))
|
||||
decl = NULL_TREE;
|
||||
}
|
||||
}
|
||||
if (decl)
|
||||
{
|
||||
field = TYPE_FIELDS (std_source_location);
|
||||
field = next_aggregate_field (field);
|
||||
/* Make sure std::source_location has exactly a single non-static
|
||||
data member (_M_impl in libstdc++, __ptr_ in libc++) with pointer
|
||||
type. Return {._M_impl = &*.Lsrc_locN}. */
|
||||
if (field != NULL_TREE
|
||||
&& POINTER_TYPE_P (TREE_TYPE (field))
|
||||
&& !next_aggregate_field (DECL_CHAIN (field)))
|
||||
{
|
||||
tree call = build_call_nary (TREE_TYPE (TREE_TYPE (decl)), decl, 0);
|
||||
SET_EXPR_LOCATION (call, rloc);
|
||||
call = fold_builtin_source_location (call);
|
||||
return build_constructor_single (std_source_location, field, call);
|
||||
}
|
||||
}
|
||||
return build_constructor (std_source_location, nullptr);
|
||||
}
|
||||
|
||||
/* If R is (const T &) &foo, get foo. */
|
||||
|
||||
static tree
|
||||
@@ -2665,7 +2667,7 @@ eval_constant_of (location_t loc, const constexpr_ctx *ctx, tree r,
|
||||
tree fun)
|
||||
{
|
||||
if (eval_is_annotation (r) == boolean_true_node)
|
||||
r = TREE_VALUE (TREE_VALUE (r));
|
||||
r = tree_strip_any_location_wrapper (TREE_VALUE (TREE_VALUE (r)));
|
||||
else if (!check_splice_expr (loc, UNKNOWN_LOCATION, r,
|
||||
/*address_p=*/false,
|
||||
/*member_access_p=*/false,
|
||||
@@ -3590,7 +3592,8 @@ eval_display_string_of (location_t loc, const constexpr_ctx *ctx, tree r,
|
||||
TREE_VEC_ELT (r, 4) == boolean_true_node
|
||||
? "true" : "false");
|
||||
else if (eval_is_annotation (r) == boolean_true_node)
|
||||
pp_printf (&pp, "[[=%E]]", TREE_VALUE (TREE_VALUE (r)));
|
||||
pp_printf (&pp, "[[=%E]]",
|
||||
tree_strip_any_location_wrapper (TREE_VALUE (TREE_VALUE (r))));
|
||||
else
|
||||
pp_string (&pp, "<unsupported reflection>");
|
||||
#if __GNUC__ >= 10
|
||||
|
||||
@@ -5941,9 +5941,13 @@ handle_annotation_attribute (tree *node, tree ARG_UNUSED (name),
|
||||
}
|
||||
if (!processing_template_decl)
|
||||
{
|
||||
location_t loc = EXPR_LOCATION (TREE_VALUE (args));
|
||||
TREE_VALUE (args) = cxx_constant_value (TREE_VALUE (args));
|
||||
if (TREE_VALUE (args) == error_mark_node)
|
||||
*no_add_attrs = true;
|
||||
auto suppression
|
||||
= make_temp_override (suppress_location_wrappers, 0);
|
||||
TREE_VALUE (args) = maybe_wrap_with_location (TREE_VALUE (args), loc);
|
||||
}
|
||||
ATTR_UNIQUE_VALUE_P (args) = 1;
|
||||
return NULL_TREE;
|
||||
|
||||
@@ -160,3 +160,15 @@ static_assert (annotations_of (bases_of (^^M <J, K, L>, ctx)[4]).size () == 3);
|
||||
static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[4])[0]) == ^^unsigned);
|
||||
static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[4])[1]) == ^^const V);
|
||||
static_assert (type_of (annotations_of (bases_of (^^M <J, K, L>, ctx)[4])[2]) == ^^long long);
|
||||
|
||||
template <auto ...V>
|
||||
consteval auto
|
||||
qux ()
|
||||
{
|
||||
[[=1, =V..., =2]] int an;
|
||||
return ^^an;
|
||||
}
|
||||
|
||||
static_assert (annotations_of (qux <> ()).size () == 2);
|
||||
static_assert (annotations_of (qux <3, 4, 5> ()).size () == 5);
|
||||
static_assert (annotations_of (qux <V { 1, 2, 3 }, V { 2, 3, 4 }> ()).size () == 4);
|
||||
|
||||
@@ -69,7 +69,8 @@ struct [[=E ()]] I // { dg-error "annotation does not have structural type" }
|
||||
[[=E ()]] int I::i4 = 0; // { dg-error "annotation does not have structural type" }
|
||||
struct J : [[=E ()]] C {}; // { dg-error "annotation does not have structural type" }
|
||||
template <typename T>
|
||||
concept K [[=E ()]] = requires { true; }; // { dg-error "annotation does not have structural type" }
|
||||
concept K [[=E ()]] = requires { true; }; // { dg-error "annotation does not have structural type" "" { xfail *-*-* } }
|
||||
constexpr bool k = K <int>;
|
||||
typedef int L [[=E ()]]; // { dg-error "annotation does not have structural type" }
|
||||
template <typename T>
|
||||
struct M {};
|
||||
|
||||
@@ -32,17 +32,30 @@ static_assert (source_location_of (dealias (^^I)).line () == std::source_locatio
|
||||
typedef S J;
|
||||
static_assert (source_location_of (dealias (^^J)).line () == source_location_of (^^S).line ());
|
||||
static_assert (source_location_of (data_member_spec (^^int, { .name = "_" })).line () == std::source_location ().line ());
|
||||
constexpr auto ctx = access_context::current ();
|
||||
struct V {};
|
||||
struct W : public S, virtual V {};
|
||||
static_assert (source_location_of (bases_of (^^W, access_context::current ())[0]).line () == std::source_location::current ().line () - 1);
|
||||
static_assert (source_location_of (bases_of (^^W, access_context::current ())[1]).line () == std::source_location::current ().line () - 2);
|
||||
struct Y { int a, b, c; };
|
||||
struct W : [[=1]] public S, [[=2, =Y { 42, 42, 42 }]] virtual V {};
|
||||
static_assert (source_location_of (bases_of (^^W, ctx)[0]).line () == std::source_location::current ().line () - 1);
|
||||
static_assert (source_location_of (bases_of (^^W, ctx)[1]).line () == std::source_location::current ().line () - 2);
|
||||
static_assert (source_location_of (annotations_of (bases_of (^^W, ctx)[0])[0]).line () == std::source_location::current ().line () - 3);
|
||||
static_assert (source_location_of (annotations_of (bases_of (^^W, ctx)[1])[1]).line () == std::source_location::current ().line () - 4);
|
||||
struct X : public S,
|
||||
public V
|
||||
[[=3]] public V
|
||||
{
|
||||
};
|
||||
static_assert (source_location_of (bases_of (^^X, access_context::current ())[0]).line () == std::source_location::current ().line () - 4);
|
||||
static_assert (source_location_of (bases_of (^^X, ctx)[0]).line () == std::source_location::current ().line () - 4);
|
||||
// TODO: we don't track location of base specifiers, so just location of the derived class definition is used.
|
||||
static_assert (source_location_of (bases_of (^^X, access_context::current ())[1]).line () == std::source_location::current ().line () - 6);
|
||||
static_assert (source_location_of (bases_of (^^X, ctx)[1]).line () == std::source_location::current ().line () - 6);
|
||||
static_assert (source_location_of (annotations_of (bases_of (^^X, ctx)[1])[0]).line () == std::source_location::current ().line () - 6);
|
||||
[[=1]]
|
||||
[[=2]] extern int an;
|
||||
[[=Y { 1, 2, 3 }]] extern int an;
|
||||
[[=3.0f + 4.0f]] int an;
|
||||
static_assert (source_location_of (annotations_of (^^an)[0]).line () == std::source_location::current ().line () - 4);
|
||||
static_assert (source_location_of (annotations_of (^^an)[1]).line () == std::source_location::current ().line () - 4);
|
||||
static_assert (source_location_of (annotations_of (^^an)[2]).line () == std::source_location::current ().line () - 4);
|
||||
static_assert (source_location_of (annotations_of (^^an)[3]).line () == std::source_location::current ().line () - 4);
|
||||
|
||||
#include <string_view>
|
||||
|
||||
@@ -77,3 +90,24 @@ bar (int a, int b)
|
||||
static_assert (std::string_view (source_location_of (d).function_name ())
|
||||
== std::string_view (source_location_of (^^a).function_name ()));
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void
|
||||
qux ()
|
||||
{
|
||||
[[=1]]
|
||||
[[=N + 42]]
|
||||
[[=Y { N, N + 1, N + 2 }]]
|
||||
[[=Y { 1, 2, 3 }]] int an;
|
||||
static_assert (N && source_location_of (annotations_of (^^an)[0]).line () == std::source_location::current ().line () - 4);
|
||||
static_assert (N && source_location_of (annotations_of (^^an)[1]).line () == std::source_location::current ().line () - 4);
|
||||
// static_assert (N && source_location_of (annotations_of (^^an)[2]).line () == std::source_location::current ().line () - 4);
|
||||
// static_assert (N && source_location_of (annotations_of (^^an)[3]).line () == std::source_location::current ().line () - 4);
|
||||
}
|
||||
|
||||
void
|
||||
plugh ()
|
||||
{
|
||||
qux <1> ();
|
||||
qux <2> ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user