return true;
}
+/* Helper function for duplicate_decls and push_local_extern_decl_alias.
+ Merge parameter attributes and names between NEWDECL and OLDDECL.
+ NEW_DEFINES_FUNCTION and TYPES_MATCH argument like variables in
+ duplicate_decls, EXTERN_ALIAS false for duplicate_decls and true for
+ push_local_extern_decl_alias. */
+
+void
+merge_decl_arguments (tree newdecl, tree olddecl, bool new_defines_function,
+ bool types_match, bool extern_alias)
+{
+ tree oldarg, newarg;
+ for (oldarg = DECL_ARGUMENTS (olddecl), newarg = DECL_ARGUMENTS (newdecl);
+ oldarg && newarg;
+ oldarg = DECL_CHAIN (oldarg), newarg = DECL_CHAIN (newarg))
+ {
+ DECL_ATTRIBUTES (newarg)
+ = (*targetm.merge_decl_attributes) (oldarg, newarg);
+ if (lookup_attribute (NULL, "indeterminate", DECL_ATTRIBUTES (newarg))
+ && !lookup_attribute (NULL, "indeterminate",
+ DECL_ATTRIBUTES (oldarg)))
+ {
+ auto_diagnostic_group d;
+ error_at (DECL_SOURCE_LOCATION (newarg),
+ "%<indeterminate%> attribute not specified for parameter "
+ "%qD on the first declaration of its function", newarg);
+ inform (DECL_SOURCE_LOCATION (oldarg), "earlier declaration");
+ }
+ /* ??? Should attributes propagate out from a block extern? If so,
+ we should do that for the function itself, not just parameters. */
+ if (!extern_alias || flag_reflection)
+ DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
+ /* Merge names for std::meta::has_identifier and
+ std::meta::{,u8}identifier_of purposes. If they are different and
+ both oldarg and newarg are named, add flag to force that
+ std::meta::has_identifier returns false. If one is named and one is
+ unnamed, if neither is a olddecl nor newdecl is definition, propagate
+ DECL_NAME to both. Otherwise stash the old name into "old parm name"
+ artificial attribute. */
+ if (flag_reflection && DECL_NAME (oldarg) != DECL_NAME (newarg))
+ {
+ if (DECL_NAME (oldarg) && DECL_NAME (newarg))
+ {
+ /* Different names. */
+ MULTIPLE_NAMES_PARM_P (oldarg) = 1;
+ MULTIPLE_NAMES_PARM_P (newarg) = 1;
+ }
+ else if (!new_defines_function
+ && types_match
+ && DECL_INITIAL (olddecl) == NULL_TREE)
+ {
+ /* For 2 non-definitions with matching types, one is named and
+ one unnamed, propagate name to both. */
+ if (DECL_NAME (oldarg))
+ DECL_NAME (newarg) = DECL_NAME (oldarg);
+ else
+ DECL_NAME (oldarg) = DECL_NAME (newarg);
+ }
+ /* Depending on which PARM_DECL we'll keep, look at the other
+ PARM_DECL's name. */
+ else if (tree name = ((new_defines_function || !types_match)
+ ? DECL_NAME (oldarg) : DECL_NAME (newarg)))
+ {
+ tree opn = lookup_attribute ("old parm name",
+ DECL_ATTRIBUTES (oldarg));
+ if (opn)
+ {
+ if (TREE_VALUE (TREE_VALUE (opn)) == name)
+ /* Name already in "old parm name" attribute. */;
+ else
+ {
+ /* Different names. */
+ MULTIPLE_NAMES_PARM_P (oldarg) = 1;
+ MULTIPLE_NAMES_PARM_P (newarg) = 1;
+ }
+ }
+ else
+ {
+ /* Save name into attribute. */
+ DECL_ATTRIBUTES (newarg)
+ = tree_cons (get_identifier ("old parm name"),
+ tree_cons (NULL_TREE, name, NULL_TREE),
+ DECL_ATTRIBUTES (newarg));
+ DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
+ }
+ }
+ else if (extern_alias)
+ DECL_NAME (newarg) = DECL_NAME (oldarg);
+ }
+ }
+}
+
/* If NEWDECL is a redeclaration of OLDDECL, merge the declarations.
If the redeclaration is invalid, a diagnostic is issued, and the
error_mark_node is returned. Otherwise, OLDDECL is returned.
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
- tree parm;
-
- /* Merge parameter attributes. */
- tree oldarg, newarg;
- for (oldarg = DECL_ARGUMENTS (olddecl),
- newarg = DECL_ARGUMENTS (newdecl);
- oldarg && newarg;
- oldarg = DECL_CHAIN (oldarg), newarg = DECL_CHAIN (newarg))
- {
- DECL_ATTRIBUTES (newarg)
- = (*targetm.merge_decl_attributes) (oldarg, newarg);
- if (lookup_attribute (NULL, "indeterminate",
- DECL_ATTRIBUTES (newarg))
- && !lookup_attribute (NULL, "indeterminate",
- DECL_ATTRIBUTES (oldarg)))
- {
- auto_diagnostic_group d;
- error_at (DECL_SOURCE_LOCATION (newarg),
- "%<indeterminate%> attribute not specified "
- "for parameter %qD on the first declaration of "
- "its function", newarg);
- inform (DECL_SOURCE_LOCATION (oldarg),
- "earlier declaration");
- }
- DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
- /* Merge names for std::meta::has_identifier and
- std::meta::{,u8}identifier_of purposes. If they are different
- and both oldarg and newarg are named, add flag to force that
- std::meta::has_identifier returns false. If one is named and
- one is unnamed, if neither is a olddecl nor newdecl is definition,
- propagate DECL_NAME to both. Otherwise stash the old name into
- "old parm name" artificial attribute. */
- if (flag_reflection && DECL_NAME (oldarg) != DECL_NAME (newarg))
- {
- if (DECL_NAME (oldarg) && DECL_NAME (newarg))
- {
- /* Different names. */
- MULTIPLE_NAMES_PARM_P (oldarg) = 1;
- MULTIPLE_NAMES_PARM_P (newarg) = 1;
- }
- else if (!new_defines_function
- && types_match
- && DECL_INITIAL (olddecl) == NULL_TREE)
- {
- /* For 2 non-definitions with matching types,
- one is named and one unnamed, propagate name
- to both. */
- if (DECL_NAME (oldarg))
- DECL_NAME (newarg) = DECL_NAME (oldarg);
- else
- DECL_NAME (oldarg) = DECL_NAME (newarg);
- }
- /* Depending on which PARM_DECL we'll keep, look at the other
- PARM_DECL's name. */
- else if (tree name = ((new_defines_function || !types_match)
- ? DECL_NAME (oldarg) : DECL_NAME (newarg)))
- {
- tree opn = lookup_attribute ("old parm name",
- DECL_ATTRIBUTES (oldarg));
- if (opn)
- {
- if (TREE_VALUE (TREE_VALUE (opn)) == name)
- /* Name already in "old parm name" attribute. */;
- else
- {
- /* Different names. */
- MULTIPLE_NAMES_PARM_P (oldarg) = 1;
- MULTIPLE_NAMES_PARM_P (newarg) = 1;
- }
- }
- else
- {
- /* Save name into attribute. */
- DECL_ATTRIBUTES (newarg)
- = tree_cons (get_identifier ("old parm name"),
- tree_cons (NULL_TREE, name, NULL_TREE),
- DECL_ATTRIBUTES (newarg));
- DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
- }
- }
- }
- }
+ merge_decl_arguments (newdecl, olddecl, new_defines_function,
+ types_match, false);
if (DECL_TEMPLATE_INSTANTIATION (olddecl)
&& !DECL_TEMPLATE_INSTANTIATION (newdecl))
DECL_ABSTRACT_P (newdecl) = DECL_ABSTRACT_P (olddecl);
/* Update newdecl's parms to point at olddecl. */
- for (parm = DECL_ARGUMENTS (newdecl); parm;
+ for (tree parm = DECL_ARGUMENTS (newdecl); parm;
parm = DECL_CHAIN (parm))
DECL_CONTEXT (parm) = olddecl;
--- /dev/null
+// PR c++/123825
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Test std::meta::identifier_of.
+
+#include <meta>
+
+void foo (int, int x, int y, int z);
+
+int
+bar (int, int x, int y, int z, int)
+{
+ return x + y + z;
+}
+
+constexpr auto foo1 = parameters_of (^^foo)[0];
+constexpr auto foo2 = parameters_of (^^foo)[1];
+constexpr auto foo3 = parameters_of (^^foo)[2];
+constexpr auto foo4 = parameters_of (^^foo)[3];
+constexpr auto bar1 = parameters_of (^^bar)[0];
+constexpr auto bar2 = parameters_of (^^bar)[1];
+constexpr auto bar3 = parameters_of (^^bar)[2];
+constexpr auto bar4 = parameters_of (^^bar)[3];
+constexpr auto bar5 = parameters_of (^^bar)[4];
+static_assert (!has_identifier (foo1));
+static_assert (identifier_of (foo2) == std::string_view ("x"));
+static_assert (identifier_of (foo3) == std::string_view ("y"));
+static_assert (identifier_of (foo4) == std::string_view ("z"));
+static_assert (!has_identifier (bar1));
+static_assert (identifier_of (bar2) == std::string_view ("x"));
+static_assert (identifier_of (bar3) == std::string_view ("y"));
+static_assert (identifier_of (bar4) == std::string_view ("z"));
+static_assert (!has_identifier (bar5));
+
+void
+baz ()
+{
+ void foo (int w, int, int v, int z);
+ int bar (int, int, int v, int z, int u);
+ void qux (int, int x, int y, int z);
+ constexpr auto qux1 = parameters_of (^^qux)[0];
+ constexpr auto qux2 = parameters_of (^^qux)[1];
+ constexpr auto qux3 = parameters_of (^^qux)[2];
+ constexpr auto qux4 = parameters_of (^^qux)[3];
+ static_assert (!has_identifier (qux1));
+ static_assert (identifier_of (qux2) == std::string_view ("x"));
+ static_assert (identifier_of (qux3) == std::string_view ("y"));
+ static_assert (identifier_of (qux4) == std::string_view ("z"));
+}
+
+static_assert (identifier_of (foo1) == std::string_view ("w"));
+static_assert (identifier_of (foo2) == std::string_view ("x"));
+static_assert (!has_identifier (foo3));
+static_assert (identifier_of (foo4) == std::string_view ("z"));
+static_assert (!has_identifier (bar1));
+static_assert (identifier_of (bar2) == std::string_view ("x"));
+static_assert (!has_identifier (bar3));
+static_assert (identifier_of (bar4) == std::string_view ("z"));
+static_assert (identifier_of (bar5) == std::string_view ("u"));
+
+void
+fred ()
+{
+ void qux (int w, int, int v, int z);
+ constexpr auto qux1 = parameters_of (^^qux)[0];
+ constexpr auto qux2 = parameters_of (^^qux)[1];
+ constexpr auto qux3 = parameters_of (^^qux)[2];
+ constexpr auto qux4 = parameters_of (^^qux)[3];
+ static_assert (identifier_of (qux1) == std::string_view ("w"));
+ static_assert (identifier_of (qux2) == std::string_view ("x"));
+ static_assert (!has_identifier (qux3));
+ static_assert (identifier_of (qux4) == std::string_view ("z"));
+}