Hi Jason:
> That sounds right for the template itself, but we call decl_attributes
> again for instantiations (under apply_late_template_attributes). Why
> doesn't targetm.insert_attributes do the right thing at that point?
It is called there and it does see the attribute, but the tag then lands
on the instantiation, and a tag on an instantiation does not affect the
name. doc/extend.texi says so for abi_tag:
The ABI tags apply to a name, so all instantiations and
specializations of a template have the same tags. The attribute is
ignored if applied to an explicit specialization or instantiation.
write_unqualified_name implements that by taking the tags from the
primary template, so that a use can be mangled before the specialization
has been seen. It shows with a plain abi_tag on any target:
template <typename T> void prim (T) {}
template <> __attribute__((abi_tag("spec"))) void prim<int> (int) {}
$ g++ -S t.C
_Z4primIiEvT_ # the tag is dropped
To affect the name the tag has to be on the pattern, and that is the one
place insert_attributes does not get to see the attribute: at the
definition splice_template_attributes has taken it away, and by the time
it comes back (save_template_attributes) decl_attributes has already
run.
Whether that happens at all depends on the type, not on "is this a
template": is_late_template_attribute defers a type_required attribute
only when the type is dependent, and abi_tag itself is exempt there. So
the hook tags some templates and not others:
template <typename T> __attribute__((riscv_vls_cc(128))) void a (T) {}
template <typename T> __attribute__((riscv_vls_cc(128))) void b () {}
a<int> -> _Z1aIiEvT_ # no tag
b<int> -> _Z1bB16riscv_vls_cc_128IiEvv
b's type is not dependent, so the attribute is never deferred, the hook
sees it at the definition and tags the pattern. a's is, so the pattern
is never tagged; the hook does see the attribute at the instantiation
and tags a<int> there, but that is exactly the tag the mangler ignores.
Same attribute, same file.
I did implement TARGET_INSERT_ATTRIBUTES before sending this patch, and
found the template behaviour above while writing the tests. One way out
is to call targetm.insert_attributes once more, after
save_template_attributes has put the deferred attributes on the decl:
```diff
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2210,7 +2210,17 @@ cplus_decl_attributes (tree *decl, tree
attributes, int flags)
}
if (late_attrs)
- save_template_attributes (late_attrs, decl, flags);
+ {
+ save_template_attributes (late_attrs, decl, flags);
+
+ /* The attributes a target reacts to may have been spliced out above, so
+ targetm.insert_attributes did not see them. They are on the
+ declaration now, so ask again for whatever they imply. */
+ tree extra = NULL_TREE;
+ targetm.insert_attributes (*decl, &extra);
+ if (extra)
+ decl_attributes (decl, extra, flags, NULL_TREE);
+ }
/* Propagate deprecation out to the template. */
if (TREE_DEPRECATED (*decl))
```
That does fix a<int>, but 11 targets already implement this hook, so
they would all have to tolerate a second call, and I am not sure that is
the right direction.
I can post the insert_attributes patches if it helps.
Thanks :)