Message ID | orzh7673v4.fsf@livre.home |
---|---|
State | New |
Headers | show |
Series | introduce attribute exalias | expand |
Ping? In case there isn't immediate approval for the patch proper (I suppose different parts will require review by different subsystem maintainers), I'd appreciate at least community and language lawyers buy-in (or turn-down) for the new feature hereby proposed for C-family languages, namely, attribute exalias("symbol_name") as a means to have symbol_name output as a same-linkage alias for functions, variables, and for C++ class types' RTTI symbols. Thanks in advance, On Aug 7, 2020, Alexandre Oliva <oliva@adacore.com> wrote: > Since last week's patchlet, I've delayed the creation of the exalias > decls, improved the merging of attributes, minimizing > interface/visibility updates, found a better way to assign exaliases to > nested explicit instantiations, even after enabling aliases to > already-defined types, so now I'm reasonably happy with the patch. > This patch introduces an attribute to add extra aliases to a symbol > when its definition is output. The main goal is to ease interfacing > C++ with Ada, as C++ mangled names have to be named, and in some cases > (e.g. when using stdint.h typedefs in function arguments) the symbol > names may vary across platforms. > The attribute is usable in C and C++, presumably in all C-family > languages. It can be attached to global variables and functions. In > C++, it can also be attached to namespace-scoped variables and > functions, static data members, member functions, explicit > instantiations and specializations of template functions, members and > classes. When applied to constructors or destructor, additional > exaliases with _Base and _Del suffixes are defined for variants other > than complete-object ones. > Applying the attribute to class types is only valid in C++, and the > effect is to attach the alias to the RTTI object associated with the > class type. > While working on this, I noticed C++ didn't merge attributes of extern > local declarations with those of the namespace-scoped declaration. > I've added code to merge the attributes if there is a namespace-scoped > declaration, but if there isn't one, there won't be any merging, and > the effects are noticeable, as in the added attr-weak-1.C. I'm also > slightly concerned that an earlier local decl would go out of sync if > a subsequent local decl, say within the same or even in another > function, introduces additional attributes in the global decl. > Regstrapped on x86_64-linux-gnu. Ok to install? > (The newly-introduced attr-weak-1.c passes in C, but is marked as XFAIL > for C++, so it gets an XPASS in C; I could move it to some C++-only > subtree, or drop it altogether and file a PR instead) > for gcc/ChangeLog > * attribs.c: Include cgraph.h. > (decl_attributes): Allow late introduction of exalias in > types. > (create_exalias_decl, create_exalias_decls): New. > * attribs.h: Declare them. > (FOR_EACH_EXALIAS): New macro. > * cgraph.c (cgraph_node::create): Create exalias decls. > * varpool.c (varpool_node::get_create): Create exalias decls. > * cgraph.h (symtab_node::remap_exalias_target): New. > * symtab.c (symtab_node::remap_exalias_target): Define. > * cgraphunit.c (cgraph_node::analyze): Create alias_target > node if needed. > (analyze_functions): Fixup visibility of implicit alias only > after its node is analyzed. > * doc/extend.texi (exalias): Document for variables, functions > and types. > for gcc/ada/ChangeLog > * doc/gnat_rm/interfacing_to_other_languages.rst: Mention > attribute exalias to give RTTI symbols mnemonic names. > * doc/gnat_ugn/the_gnat_compilation_model.rst: Mention > attribute exalias. Fix incorrect ref to C1 ctor variant. > for gcc/c-family/ChangeLog > * c-ada-spec.c (pp_asm_name): Use first exalias if available. > * c-attribs.c (handle_exalias_attribute): New. > (c_common_attribute_table): Add exalias. > (handle_copy_attribute): Do not copy exalias. > * c-decl.c (duplicate_decls): Remap exalias target. > for gcc/cp/ChangeLog > * class.c (copy_fndecl_with_name): Move/adjust exalias to > cdtor variants. > (build_cdtor_clones): Drop exalias from primary variant. > * cp-tree.h (update_exalias_interface, update_tinfo_exalias): > Declare. > * decl.c (duplicate_decls): Remap exalias target. > (grokfndecl): Tentatively create exalias decls after adding > attributes in e.g. a template member function explicit > instantiation. > * decl2.c (cplus_decl_attributes): Update tinfo exalias. > (copy_interface, update_exalias_interface): New. > (determine_visibility): Update exalias interface. > (tentative_decl_linkage, import_export_decl): Likewise. > * name-lookup.c: Include target.h and cgraph.h. > (set_local_extern_decl_linkage): Merge attributes with a > namespace-scoped decl if one is found. Remap exalias > targets, and drop exaliases from the local decl. > * optimize.c (maybe_clone_body): Only copy attributes if they > haven't been copied yet. Update exalias interface. > * rtti.c: Include attribs.h and cgraph.h. > (get_tinfo_decl): Copy exalias attributes from type to tinfo > decl. Create exalias decls. > (update_tinfo_exalias): New. > for gcc/testsuite/ChangeLog > * c-c++-common/attr-weak-1.c: New, xfailed. > * c-c++-common/torture/attr-exalias-1.c: New. > * c-c++-common/torture/attr-exalias-2.c: New. > * c-c++-common/torture/attr-exalias-3.c: New. > * c-c++-common/torture/attr-exalias-4.c: New. > * g++.dg/torture/attr-exalias-1.C: New. > * g++.dg/torture/attr-exalias-2.C: New. > * g++.dg/torture/attr-exalias-3.C: New. > * g++.dg/torture/attr-exalias-4.C: New. https://gcc.gnu.org/pipermail/gcc-patches/2020-August/551614.html
On 8/14/20 11:39 AM, Alexandre Oliva wrote: > Ping? > > In case there isn't immediate approval for the patch proper (I suppose > different parts will require review by different subsystem maintainers), > I'd appreciate at least community and language lawyers buy-in (or > turn-down) for the new feature hereby proposed for C-family languages, > namely, attribute exalias("symbol_name") as a means to have symbol_name > output as a same-linkage alias for functions, variables, and for C++ > class types' RTTI symbols. This seems a useful feature. I don;t think it needs language lawyering -- it's an extension, right? By 'same-linkage', do you mean same linkage as the *symbol* of the thing it is aliasing, or same linkage as the language entity it is aliasing? I suspect you mean the former. I'm sure we can bikeshed the name 'exalias' doesn't seem very mnemonic to me. 'symbol_alias' or something? nathan > > Thanks in advance, > > On Aug 7, 2020, Alexandre Oliva <oliva@adacore.com> wrote: > >> Since last week's patchlet, I've delayed the creation of the exalias >> decls, improved the merging of attributes, minimizing >> interface/visibility updates, found a better way to assign exaliases to >> nested explicit instantiations, even after enabling aliases to >> already-defined types, so now I'm reasonably happy with the patch. > > >> This patch introduces an attribute to add extra aliases to a symbol >> when its definition is output. The main goal is to ease interfacing >> C++ with Ada, as C++ mangled names have to be named, and in some cases >> (e.g. when using stdint.h typedefs in function arguments) the symbol >> names may vary across platforms. > >> The attribute is usable in C and C++, presumably in all C-family >> languages. It can be attached to global variables and functions. In >> C++, it can also be attached to namespace-scoped variables and >> functions, static data members, member functions, explicit >> instantiations and specializations of template functions, members and >> classes. When applied to constructors or destructor, additional >> exaliases with _Base and _Del suffixes are defined for variants other >> than complete-object ones. > >> Applying the attribute to class types is only valid in C++, and the >> effect is to attach the alias to the RTTI object associated with the >> class type. > > >> While working on this, I noticed C++ didn't merge attributes of extern >> local declarations with those of the namespace-scoped declaration. >> I've added code to merge the attributes if there is a namespace-scoped >> declaration, but if there isn't one, there won't be any merging, and >> the effects are noticeable, as in the added attr-weak-1.C. I'm also >> slightly concerned that an earlier local decl would go out of sync if >> a subsequent local decl, say within the same or even in another >> function, introduces additional attributes in the global decl. > > >> Regstrapped on x86_64-linux-gnu. Ok to install? > > >> (The newly-introduced attr-weak-1.c passes in C, but is marked as XFAIL >> for C++, so it gets an XPASS in C; I could move it to some C++-only >> subtree, or drop it altogether and file a PR instead) > >> for gcc/ChangeLog > >> * attribs.c: Include cgraph.h. >> (decl_attributes): Allow late introduction of exalias in >> types. >> (create_exalias_decl, create_exalias_decls): New. >> * attribs.h: Declare them. >> (FOR_EACH_EXALIAS): New macro. >> * cgraph.c (cgraph_node::create): Create exalias decls. >> * varpool.c (varpool_node::get_create): Create exalias decls. >> * cgraph.h (symtab_node::remap_exalias_target): New. >> * symtab.c (symtab_node::remap_exalias_target): Define. >> * cgraphunit.c (cgraph_node::analyze): Create alias_target >> node if needed. >> (analyze_functions): Fixup visibility of implicit alias only >> after its node is analyzed. >> * doc/extend.texi (exalias): Document for variables, functions >> and types. > >> for gcc/ada/ChangeLog > >> * doc/gnat_rm/interfacing_to_other_languages.rst: Mention >> attribute exalias to give RTTI symbols mnemonic names. >> * doc/gnat_ugn/the_gnat_compilation_model.rst: Mention >> attribute exalias. Fix incorrect ref to C1 ctor variant. > >> for gcc/c-family/ChangeLog > >> * c-ada-spec.c (pp_asm_name): Use first exalias if available. >> * c-attribs.c (handle_exalias_attribute): New. >> (c_common_attribute_table): Add exalias. >> (handle_copy_attribute): Do not copy exalias. >> * c-decl.c (duplicate_decls): Remap exalias target. > >> for gcc/cp/ChangeLog > >> * class.c (copy_fndecl_with_name): Move/adjust exalias to >> cdtor variants. >> (build_cdtor_clones): Drop exalias from primary variant. >> * cp-tree.h (update_exalias_interface, update_tinfo_exalias): >> Declare. >> * decl.c (duplicate_decls): Remap exalias target. >> (grokfndecl): Tentatively create exalias decls after adding >> attributes in e.g. a template member function explicit >> instantiation. >> * decl2.c (cplus_decl_attributes): Update tinfo exalias. >> (copy_interface, update_exalias_interface): New. >> (determine_visibility): Update exalias interface. >> (tentative_decl_linkage, import_export_decl): Likewise. >> * name-lookup.c: Include target.h and cgraph.h. >> (set_local_extern_decl_linkage): Merge attributes with a >> namespace-scoped decl if one is found. Remap exalias >> targets, and drop exaliases from the local decl. >> * optimize.c (maybe_clone_body): Only copy attributes if they >> haven't been copied yet. Update exalias interface. >> * rtti.c: Include attribs.h and cgraph.h. >> (get_tinfo_decl): Copy exalias attributes from type to tinfo >> decl. Create exalias decls. >> (update_tinfo_exalias): New. > >> for gcc/testsuite/ChangeLog > >> * c-c++-common/attr-weak-1.c: New, xfailed. >> * c-c++-common/torture/attr-exalias-1.c: New. >> * c-c++-common/torture/attr-exalias-2.c: New. >> * c-c++-common/torture/attr-exalias-3.c: New. >> * c-c++-common/torture/attr-exalias-4.c: New. >> * g++.dg/torture/attr-exalias-1.C: New. >> * g++.dg/torture/attr-exalias-2.C: New. >> * g++.dg/torture/attr-exalias-3.C: New. >> * g++.dg/torture/attr-exalias-4.C: New. > > https://gcc.gnu.org/pipermail/gcc-patches/2020-August/551614.html >
On Aug 14, 2020, Nathan Sidwell <nathan@acm.org> wrote: > This seems a useful feature. I don;t think it needs language > lawyering -- it's an extension, right? Well, yeah, but I think it's usually good for even extensions to be sound language-wise. > By 'same-linkage', do you mean same linkage as the *symbol* of the > thing it is aliasing, or same linkage as the language entity it is > aliasing? > I suspect you mean the former. Yeah, ultimately the symbol declared as exalias gets the same object-level linkage and visibility properties as those of the primary symbol emitted for the language entity. Conceptually, the entity introduced by the attribute is not even visible or accessible in the standard language; it can only be referenced by alias attributes and by Ada import declarations, but conceptually, in as much as you conceive of it as a separate entity, I suppose it makes some sense to say it gets the same linkage as the entity it refers to. > I'm sure we can bikeshed the name 'exalias' doesn't seem very mnemonic > to me. 'symbol_alias' or something? I don't like symbol_alias; that this feature names a symbol is not a distinguishing feature from the preexisting alias attribute. 'ex' can be read as both extra, exported, external, and all of these sort of make sense, at least for entities that have linkage. Even for exclusively internal uses, say to introduce a mnemonic symbol for another alias-attributed declaration to refer to, the "ex" prefix, that means the opposite of "in", fitting in well with the functionality of "ex"posing the symbol through a name that other alias declarations can take *in*, *im*port. Another possible spelling for this proposed attribute that might be more mnemonic is "aka"; unfortunately, that's pretty much a synonym to alias, so it might be mistaken as such, rather than as a complementary feature, akin to the other end of a power extension cable: whereas alias does the job of a plug, *ex*alias provides a socket/*out*let.
On 8/14/20 3:24 PM, Alexandre Oliva wrote: > On Aug 14, 2020, Nathan Sidwell <nathan@acm.org> wrote: > >> This seems a useful feature. I don;t think it needs language >> lawyering -- it's an extension, right? > > Well, yeah, but I think it's usually good for even extensions to be > sound language-wise. > >> By 'same-linkage', do you mean same linkage as the *symbol* of the >> thing it is aliasing, or same linkage as the language entity it is >> aliasing? >> I suspect you mean the former. > > Yeah, ultimately the symbol declared as exalias gets the same > object-level linkage and visibility properties as those of the primary > symbol emitted for the language entity. Conceptually, the entity > introduced by the attribute is not even visible or accessible in the > standard language; it can only be referenced by alias attributes and by > Ada import declarations, but conceptually, in as much as you conceive of > it as a separate entity, I suppose it makes some sense to say it gets > the same linkage as the entity it refers to. thanks for the discussion. I should have said, 'exalias' sounds either like a used-to-be alias, it is an ex alias, it has ceased to be, gone to join the choir invisible. or it sounds like exa-lias, making me wonder what a 'lia' is, and why I want 10^18 of them >> I'm sure we can bikeshed the name 'exalias' doesn't seem very mnemonic >> to me. 'symbol_alias' or something? > > I don't like symbol_alias; that this feature names a symbol is not a > distinguishing feature from the preexisting alias attribute. right, I realize this is different to the existing alias. It's always struck me that the existing semantics are not c++ friendly. Perhaps alias is not the right name at all. You're emitting an alternative symbol, for use in interfacing to a foreign language/system. Perhaps 'xenoname'? > > 'ex' can be read as both extra, exported, external, and all of these > sort of make sense, at least for entities that have linkage. > > Even for exclusively internal uses, say to introduce a mnemonic symbol > for another alias-attributed declaration to refer to, the "ex" prefix, > that means the opposite of "in", fitting in well with the functionality > of "ex"posing the symbol through a name that other alias declarations > can take *in*, *im*port. > > Another possible spelling for this proposed attribute that might be more > mnemonic is "aka"; unfortunately, that's pretty much a synonym to alias, > so it might be mistaken as such, rather than as a complementary feature, > akin to the other end of a power extension cable: whereas alias does the > job of a plug, *ex*alias provides a socket/*out*let. > nathan
On Aug 14, 2020, Nathan Sidwell <nathan@acm.org> wrote: > 'exalias' sounds either like a used-to-be alias *nod* > or it sounds like exa-lias, making me wonder what a 'lia' is, and why > I want 10^18 of them heh >>> I'm sure we can bikeshed the name 'exalias' doesn't seem very mnemonic >>> to me. 'symbol_alias' or something? >> I don't like symbol_alias; that this feature names a symbol is not a >> distinguishing feature from the preexisting alias attribute. > right, I realize this is different to the existing alias. The point was that the existing alias already takes a symbol name. > It's always struck me that the existing semantics are not c++ > friendly. Indeed, avoiding the need for using mangled symbol names to refer to language entities is the very issue I've set out to solve. It helps with aliases in C++ as much as it helps with imports in Ada. > Perhaps alias is not the right name at all. I kind of like the explicit present of "alias" because, well, what we get is an alias, to the point that, if asm aliases aren't available, it won't work. And, if they are, you can use the so-assigned name as an alias target, so it's a good thing if they're typographically related. One could even argue that this new attribute is more deserving of the term alias than the existing one, and that the existing one should be renamed to "aliased_to" or so. But I'm not seriously suggesting us to rename a long-available attribute while assigning uses thereof a different semantics, that would be preposterous. Since you don't seem to have liked 'aka' either, how about 'nickname', or 'nicknamed'? A more convenient name to refer to an entity is exactly what this is about, eh?
Hi Alexandre, I built the patch on x86_64-linux and darwin*** (fwiw). * It’s firmly agreed that there are times when referring to C++ mangled names is less than ideal. * IIUC, the objective is to have a short-hand way of annotating an export from C++ so that it’s (a) more human-readable and (b) independent of any platform variation in mangling of types - in the Ada import pragma? I see Nathan commented that there are no language-lawyering implications, which is good. However, there do seem to be both ABI and engineering implications: * if the target ABI does not support symbol aliases, then this facility cannot be used. Which either means that you cannot rely on this facility (and thus make things generically easier in the Ada implementation on GCC) or you will exclude the GCC targets without symbol aliases from Ada. The latter would make me sad as Darwin maintainer. * the symbol table will grow (maybe one doesn’t care if there are not many). * The process shifts the onus on representation to the exporter and thus there can now be 3 library vendors who all thought “MY_FOO_FUNC” was the best representation for an export - these will now clash in the “shorthand” namespace, although their C++ mangling might well not. * it’s not universally usable without “rebuilding the world” and having access to source for everything you might want to import (maybe not important, depends on whether there are users of Ada who depend on closed source libraries). * what happens for templates and overloads - presumably the Ada import has add the relevant (albeit abbreviated) decorations? * One can’t have an arbitrary re-name; it has to be supported by the target assembler (not that this is a new constraint, but it prevents the exported name from being an exact representation of the human-readable C++ interface in general). —— are there other possibilites to solve the underlying issue? C++ mangled names have some proven good properties: * they convey all the relevant information about the interface * they are standardized, and work between implementations from different ‘vendors’ or OSS compilers on the same platform. * they are not going to clash. The compiler already has a proven implementation of C++ mangling rules. what about annotating the import pragma in some way such that the platform mangling is applied by the compiler? thus, in my example below, so long as the interface is represented correctly by the string after “itanium:” it will mangle correctly for the target (even if that mangling would alter between targets for representation of some types). I suppose there’s a question of how many pragmas would be needed to annotate sufficiently to get the mangling right? pragma CPP_Constructor (New_Animal); pragma Import (CPP, New_Animal, itanium:”Animal()"); It seems one ideally wants the Ada moral equivalent of: extern “C++” { things we want to import. } which automagically does the right interface transforms and synthesizes the Ada interfaces required. Alexandre Oliva <oliva@adacore.com> wrote: > On Aug 14, 2020, Nathan Sidwell <nathan@acm.org> wrote: > >> >> Perhaps alias is not the right name at all. > > I kind of like the explicit present of "alias" because, well, what we > get is an alias, to the point that, if asm aliases aren't available, it > won't work. And, if they are, you can use the so-assigned name as an > alias target, so it's a good thing if they're typographically related. > > One could even argue that this new attribute is more deserving of the > term alias than the existing one, and that the existing one should be > renamed to "aliased_to" or so. But I'm not seriously suggesting us to > rename a long-available attribute while assigning uses thereof a > different semantics, that would be preposterous. > > Since you don't seem to have liked 'aka' either, how about 'nickname', > or 'nicknamed'? A more convenient name to refer to an entity is exactly > what this is about, eh? .. assuming this facility was added ... .. my 0.02GBP contribution the the bikeshed painting fund would be…. it’s nice when an attribute reads in the source to tell you its purpose. so how about: “export_as” or “exported_as” (depending on whether one regards this as a command to the compiler, or an annotation). so : __attribute__ ((__export_as__ ("Ctor_For_Animal"))) // extra alias Animal() {Age_Count = 0;}; or: __attribute__ ((__exported_as__ ("Ctor_For_Animal"))) // extra alias Animal() {Age_Count = 0;}; thanks Iain *** right now Darwin fails silently (there doesn’t seem to be the usual error that the target doesn’t support that kind of alias).
On Aug 15, 2020, Iain Sandoe <iain@sandoe.co.uk> wrote: > * if the target ABI does not support symbol aliases, then this facility cannot > be used. True. I'm surprised there are modern platforms that don't. What is it that stands in the way? Lack of support for .set in the assembler? If that's the case, couldn't it possibly be worked around by setting multiple global labels at the same spot? I'm pretty sure setting multiple labels at the same address is used and relied on quite often. > will exclude the GCC targets without symbol aliases from Ada. It's not so dire. Developers for alias-deprived systems would have to use the mangled names instead. That would be a little painful, but not even close to making the language unavailable. > * The process shifts the onus on representation to the exporter and thus there > can now be 3 library vendors who all thought “MY_FOO_FUNC” was the > best representation for an export - these will now clash in the “shorthand” > namespace, although their C++ mangling might well not. Using this to disqualify the new feature would also disqualify regular aliases, that could be used for just the same purpose of making symbols available under chosen names: extern "C" typeof(foo::func) __attribute__((__alias__("<mangling for foo::func>"))) MY_FOO_FUNC; Now, this concern appears to be focused on binary-only libraries. Since we haven't seen vendors rush to make their library internals available under shorter aliases, polluting the symbolic namespace, I see little reason for concern about this possibility. When it comes to binary-only libraries, the ABI is often set in stone, and it's up to users to figure out the symbol names in the ABI and use them. If they vary across target platforms, that's inconvenient, but nothing new. I expect this feature to be used and useful within multi-language projects, particularly when using, as part of their interfaces, shorthand typedefs whose encoding varies depending on the platform. E.g., consider a function or a template instantiation that takes a int64_t parameter. Depending on whether int64_t maps to long or long long, you get different encodings, thus references using the symbol name have to be adjusted depending on what type stdint.h maps int64_t to. > * it’s not universally usable without “rebuilding the world” and having access to > source for everything you might want to import You mean it does not bring improvements to situations in which you can't introduce nicknames for third-party symbols. You then figure out and import the mangled names and move on. > * what happens for templates and overloads - presumably the Ada import has > add the relevant (albeit abbreviated) decorations? They don't matter to the proposed design. The reason they come up for you is that you have a completely different solution in mind that requires this kind of resolution. The one I'm proposing attaches the extra aliases directly to the target language entity, be it one of the overloads of a member function, be it a specialization of a template function. > * One can’t have an arbitrary re-name; it has to be supported by the target > assembler (not that this is a new constraint, but it prevents the exported > name from being an exact representation of the human-readable C++ interface > in general). *nod*. It couldn't be a target for alias attributes otherwise, and I found that a desirable property to make the new feature useful even for standalone C++. > —— are there other possibilites to solve the underlying issue? > C++ mangled names have some proven good properties: > * they convey all the relevant information about the interface > * they are standardized, and work between implementations from different > ‘vendors’ or OSS compilers on the same platform. > * they are not going to clash. * they require so much symbolic information that in order to perform mangling you pretty much have to #include all of the relevant C++ headers. Consider typedefs, templates with partial or explicit specializations, default template arguments, besides the possibility of varying definitions across platforms. > what about annotating the import pragma in some way such that the platform > mangling is applied by the compiler? That would indeed be desirable, but it is unfortunately not viable. Consider you have to figure out the correct mangling for this: foo::bar<std::iostream&, std::string, u64, g::h>::f Is foo a namespace, a canonical class name, or a typedef? (maybe even a using declaration, or even something brought into the global namespace by a using directive) If it's a typedef, what's the canonical name? (it could be a template instantiation) bar is clearly a template type, so you "just" need enough symbolic information to be able to mangle std::iostream&, std::string, u64, g::h. For u64, you just have to look at stdint.h to see which of the C++-defined types is maps to. g::h is a mystery. It could be a type, a function, a member function, a variable, a data member... There could be any subsequent template parameters using defaults. Even if we were to simplify this (and make it inconvenient for the user) requiring no defaults to be relied on, that wouldn't get you much farther. Finally, we get to f. We can assume it's not a template type, nor a template member function, so it would have to be (assuming a well-formed symbolic reference) a static or non-static data member, a static or non-static member function, a typedef, a nested type; possibly a template instantiation, using defaults?). It could even name an overload set, so you might want to require a parameter list, and an explicit template parameter list. We could then require all of this symbolic information, in the form of type, variable and function declarations, including partial and explicit specializations, and the transitive closure thereof. How would you get all of this symbolic information to the compiler of the Ada unit importing such C++ symbols? Parsing C++ headers? Requiring users to bring the relevant declarations into the Ada program? Searching the symbol tables of object files that would have to have alreayd been compiled, looking for a match? None of these are good. Extracting symbolic information from C++ headers (à-la -fdump-ada-spec, but with a *lot* more symbolic info) in a first pass, and referencing that in your imports. Viable, a *lot* of work, and also a big doh! -fdump-ada-spec would already get you the Imports with the mangled names. This feature is for when you don't want to go through all this trouble, and would rather reference a few C++ symbols directly in your target-independent sources. > it’s nice when an attribute reads in the source to tell you its purpose. *exporting* is heavily overloaded, so I've been avoiding it. One thing the proposed feature does NOT do is to make the alias more visible than the original symbol. If it's internal, hidden or protected, or even if it's local, it won't get exported. You could use it, and then another alias declaration referencing it, to get it exported, if you wish, but that was enough of a reason for me to stay away from the term "export". > *** right now Darwin fails silently (there doesn’t seem to be the usual error > that the target doesn’t support that kind of alias). Hmm, thanks, I will make sure there's some more verbose failure mode if we can't find a way for something akin to an alias to be usable there.
On Aug 15, 2020, Iain Sandoe <iain@sandoe.co.uk> wrote: > what about annotating the import pragma in some way such that the platform > mangling is applied by the compiler? Oh, one more thing about this. Requiring all names to be given in canonical form might alleviate some of the problems I raised, since it would eliminate typedefs and using declarations and directives from consideration. We'd still have other unsurmountable problems to deal with, but more importantly, you wouldn't be able to use u64 any more, you'd have to resolve it to the type that u64 is mapped to, at which point you'd be bringing back the very variation across targets that this feature was designed to overcome.
HI Alexandre I don’t want to derail the discussion - but FIO mostly…. Alexandre Oliva <oliva@adacore.com> wrote: > On Aug 15, 2020, Iain Sandoe <iain@sandoe.co.uk> wrote: > >> * if the target ABI does not support symbol aliases, then this facility >> cannot >> be used. > > True. I'm surprised there are modern platforms that don’t. different platforms have different designs - it’s not an “old c.f new” thing - see below. > What is it that stands in the way? Lack of support for .set in the > assembler? > If that's the case, couldn't it possibly be worked around by > setting multiple global labels at the same spot? I'm pretty sure > setting multiple labels at the same address is used and relied on quite > often. That’s what’s currently disallowed (the assemblers all support .set). Long ago (before my time with GCC) Darwin’s toolchains did support aliases. The withdrawal was not an accident, but a design choice - where a linker model based on “atoms” was chosen (which requires [as things stand] public symbols to have distinct addresses). I can point you at a description of the linker optimisation if you’re interested. IMO, the atom model can be modified to allow aliases (it might be even that the linker constraint has been relaxed already). However, it’s not my call - I’ve suggested to the platform toolchain team it’s a good idea, but it doesn’t seem to block any other toolchain than GCC so not sure what priority would be assigned. For function aliases, I think there’s a simple work-around and it’s just a question of time for me to make a patch etc. for general aliases to public symbols including data, not so easy. >> will exclude the GCC targets without symbol aliases from Ada. > > It's not so dire. Developers for alias-deprived systems would have to > use the mangled names instead. That would be a little painful, but not > even close to making the language unavailable. Well the predicate was that the use of the mechanism was mandatory, if the existing scheme continues of course there’s no issue. >> * The process shifts the onus on representation to the exporter and thus >> there >> can now be 3 library vendors who all thought “MY_FOO_FUNC” was the >> best representation for an export - these will now clash in the “shorthand” >> namespace, although their C++ mangling might well not. > > Using this to disqualify the new feature would also disqualify regular > aliases, that could be used for just the same purpose of making symbols > available under chosen names: It wasn’t a comment against the feature - but a comment about shifting the onus for export information onto the producers (and the fact that one can’t generally control what they choose to provide in the absence of a specification - which itanium mangling is). >> * what happens for templates and overloads - presumably the Ada import has >> add the relevant (albeit abbreviated) decorations? > > They don't matter to the proposed design. The reason they come up for > you is that you have a completely different solution in mind that > requires this kind of resolution. The one I'm proposing attaches the > extra aliases directly to the target language entity, be it one of the > overloads of a member function, be it a specialization of a template > function. Actually, I was thinking about folks who like template metaprogramming (not personally a fan) - and how they would arrange to get automatic export information to track that meta-progamming. Solved if one were able to import the interface…. >> —— are there other possibilites to solve the underlying issue? > >> C++ mangled names have some proven good properties: > >> * they convey all the relevant information about the interface >> * they are standardized, and work between implementations from different >> ‘vendors’ or OSS compilers on the same platform. >> * they are not going to clash. > > * they require so much symbolic information that in order to perform > mangling you pretty much have to #include all of the relevant C++ > headers. > > Consider typedefs, templates with partial or explicit specializations, > default template arguments, besides the possibility of varying > definitions across platforms. > >> what about annotating the import pragma in some way such that the platform >> mangling is applied by the compiler? > > That would indeed be desirable, but it is unfortunately not viable. <snipped explanation> I see. Thinking aloud - not thought through in any detail - I wonder if the facilities of C++20 modules are sufficient? >> *** right now Darwin fails silently (there doesn’t seem to be the usual >> error >> that the target doesn’t support that kind of alias). > > Hmm, thanks, I will make sure there's some more verbose failure mode if > we can't find a way for something akin to an alias to be usable there. I imagine it will be easy to fix a diagnostic output. Iain
On 8/14/20 10:43 PM, Alexandre Oliva wrote: > On Aug 14, 2020, Nathan Sidwell <nathan@acm.org> wrote: > Since you don't seem to have liked 'aka' either, how about 'nickname', > or 'nicknamed'? A more convenient name to refer to an entity is exactly > what this is about, eh? I'm sorry, I think those are awful names. They convey no intent. C++ already has at least 2 'nickname' mechanisms: using bob = ::foo::bar<bob::random_type,int>; auto &bill = ::elsewhere::object<some_type>; 'alias' is also now a confusing term, because of the concept of object-aliasing. The existing alias attribute is defined as: > The @code{alias} attribute causes the declaration to be emitted as an alias > for another symbol, which must have been previously declared with the same > type, and for variables, also the same size and alignment. Declaring an alias > with a different type than the target is undefined and may be diagnosed. As > an example, the following declarations: I.e. it is creating a declaration that is aliased to some other symbol (which has to also be emitted by the same TU due to the usual elf-like object file semantics). Notice it says nothing about emitting a *symbol*. The new attribute is emitting a symbol that equates the declaration it is attached to (i.e. the other way round). Its intent is to allow code written in another language to refer to this definition. I imagine you'd commonly use the foreign language's mangling for the string provided. If we spell it 'X', consider: [[gnu::X ("other")]] int i; Most commonly, the assembly emitted would contain: .globl other .equiv other, i so, perhaps we should spell it 'equiv'? That's using an existing term. nathan
On Aug 15, 2020, Nathan Sidwell <nathan@acm.org> wrote: > 'alias' is also now a confusing term, because of the concept of object-aliasing. True, but it's also an established attribute name. It seems thus desirable to bring the conceptual framework of the alias attribute to mind through the name of the attribute used in this new feature, but with a twist that distinguishes it from the original attribute in a meaningful way. > The existing alias attribute is defined as: >> The @code{alias} attribute causes the declaration to be emitted as an alias >> for another symbol, which must have been previously declared with the same >> type, and for variables, also the same size and alignment. Declaring an alias >> with a different type than the target is undefined and may be diagnosed. As >> an example, the following declarations: > I.e. it is creating a declaration that is aliased to some other symbol > (which has to also be emitted by the same TU due to the usual elf-like > object file semantics). Notice it says nothing about emitting a > *symbol*. It's an implied expectation that declarations of language entities get symbols associated with them, and that attribute alias causes the symbol name associated with one declaration to refer to the same entity denoted by the named symbol, instead of introducing a separate entity. > The new attribute is emitting a symbol that equates the declaration it > is attached to (i.e. the other way round). I.e., now we have a single declaration of a language entity, and we wish additional symbol names to be associated with it. > Its intent is to allow code written in another language to refer to > this definition. I imagine you'd commonly use the foreign language's > mangling for the string provided. What I have in mind are mnemonic, user-chosen names, rather than machine-mangled ones. > If we spell it 'X', consider: > [[gnu::X ("other")]] int i; > Most commonly, the assembly emitted would contain: > .globl other > .equiv other, i > so, perhaps we should spell it 'equiv'? That's using an existing term. Uhh, my turn to find the term meaningless. Not just because on my machines, aliases use .set rather than .equiv. It's missing about as much context as 'aka' and 'nickname' in the relationship to alias. The problem we face is that alias is a symmetric relationship, in that if X aliases Y, then Y aliases X, but attribute alias is not symmetric: its attribute must be placed in an undefined declaration, naming the already-defined entity. It would have made just as much sense to make it work backwards, namely, attaching the attribute to the defined entity, naming any other undefined declarations that ought to refer to the same entity. That's pretty much the attribute I propose. Thus clearly, though "alias" is symmetric, our use thereof isn't. Our implementation uses the phrase "alias target" to refer to the already-defined entity that a declaration holding an alias attribute should alias; the declaration holding the alias attribute is referred to as an alias. Since attribute alias is already taken, it would thus make sense to look for opposites of alias target to denote the new attribute. Alias source and alias origin are probably the most natural opposites of alias target, but they don't suggest to me what we're looking for. Alias lead might work. Alias bead might, too. OTOH, since the alias attribute is associated with the alias declaration, and it names an alias target; the opposite of that, with an attribute in the alias target declaration, would best have the attribute named alias_target (that's an attribute of the declaration, after all), and then the named symbol would be the alias. This would be surprisingly consistent with the current use of attribute alias: int attribute((alias_target("Y"))) X; // X is the alias target for Y int attribute((alias("Y"))) Z; // Z is an alias for Y Now, if we were to use "equiv", it would make sense to think of the current alias attribute as "equiv_to" / "alias_target". Another possibility that occurs to me is to reuse the existing attribute alias, but naming the equivalent symbol as a second parameter to attribute alias, suggesting a relation alias(X,Y), building on the existing alias(X) in which the Y is implied, and introducing a variant in which it is the X that is implied. Alas, an explicit placeholder is needed in this case. Hmm, maybe such a two-argument variant of alias could be made more readable by requiring the *second* argument to be number 2: int attribute((alias("Y", 2))) X; reading as imperative "alias Y to X", whereas existing uses: int attribute((alias("Y"))) Z; read as imperative "alias Y Z", nonsense, but taken as "alias Z to Y", perhaps by analogy with how "give Y Z" is taken as "give Z to Y". /me jokingly suggests inhalias and exhalias ;-) This is enough bikeshedding for me ;-)
On Aug 15, 2020, Iain Sandoe <iain@sandoe.co.uk> wrote: > Alexandre Oliva <oliva@adacore.com> wrote: >> I'm pretty sure setting multiple labels at the same address is used >> and relied on quite often. > That’s what’s currently disallowed (the assemblers all support .set). I understand you mean it's disallowed for global labels. I meant it was often used for local labels. > For function aliases, I think there’s a simple work-around and it’s just a > question of time for me to make a patch etc. Yeah, one possibility that comes to mind is to output additional text symbols (akin to PLT entries) that just jump to the intended target. > for general aliases to public symbols including data, not so easy. *nod* As far as I'm concerned, function aliases as above would be enough to address the issue I was asked to address. The RTTI aliases are only used to import and catch C++ exception in Ada. I suppose a mnemonic would be just as welcome, but if it's not available, the mangled name will have to do. > Actually, I was thinking about folks who like template metaprogramming > (not personally a fan) - and how they would arrange to get automatic > export information to track that meta-progamming. There's no (current) way to import C++ templates as Ada generics; the best you can do is to import C++ template instantiations/specializations as Ada records, procedures and functions. This, and the lack of a symbolic representation of generics, has driven me to introduce user-chosen named aliases for specializations, rather than to the generics. I've considered enabling symbolic mnemonic template names to be associated with templates, say: template <typename T, typename U> struct foo { static void __attribute__((__exalias__("FOO_%<T>_%<U>_static_method"))) static_method () {} }; replacing %<T> and %<U> with the mangling for the template arguments, but that would bring us back the problem of varying mangled names as mnemonic types like u64 get resolved to the mangling of their target-dependent language types, defeating the purpose of referencing cross-platform symbol names from Ada. > Thinking aloud - not thought through in any detail - I wonder if the > facilities of > C++20 modules are sufficient? I'm really not sure what issue you're thinking of solving. The one I'm working on is that of enabling the use of a uniform string in Ada import statements (and also in alias("targets")), even when a symbolic type that does not mangle uniformly is in use (think int64_t mapping to long or long long). Having per-target source files is quite cumbersome in Ada, and there isn't a preprocessor to rely on for conditionals and token pasting and whatnot. I'm afraid I don't see how C++ modules could any offer in this regard. >> Hmm, thanks, I will make sure there's some more verbose failure mode if >> we can't find a way for something akin to an alias to be usable there. > I imagine it will be easy to fix a diagnostic output. *nod*
Alexandre Oliva <oliva@adacore.com> wrote: > On Aug 15, 2020, Iain Sandoe <iain@sandoe.co.uk> wrote: > >> Alexandre Oliva <oliva@adacore.com> wrote: > >>> I'm pretty sure setting multiple labels at the same address is used >>> and relied on quite often. > >> That’s what’s currently disallowed (the assemblers all support .set). > > I understand you mean it's disallowed for global labels. Yes - or, in fact, linker-visible ones for Darwin because of the issue below. > I meant it was often used for local labels. … including for Darwin targets; one has to take care with details sometimes, since a local label defines something that is part of the atom delineated by the next preceding global (or linker-visible) symbol (or section start if there are none). When the local label does not really belong to that atom, it can cause problems (e.g. apparently branching to code that is weak global) so we insert a non-global (but linker-visible) symbol to allow a new atom to start. >> Thinking aloud - not thought through in any detail - I wonder if the >> facilities of >> C++20 modules are sufficient? > > I'm really not sure what issue you're thinking of solving. The one where one wanted to import the declaration of a function without having to include every header needed to declare the types it uses. Since a header unit should be self-contained and is a compiled artefact. > The one I'm working on is that of enabling the use of a uniform string > in Ada import statements (and also in alias("targets")), even when a > symbolic type that does not mangle uniformly is in use (think int64_t > mapping to long or long long). Having per-target source files is quite > cumbersome in Ada, and there isn't a preprocessor to rely on for > conditionals and token pasting and whatnot. > > I'm afraid I don't see how C++ modules could any offer in this regard. perhaps not, it was only “thinking aloud” (since we are agreed it would be nice to have a solution that the compiler could manipulate/synthesize, rather than requiring source-level changes). FAOD, the comments above are just continuation of discussion - not any additional objection to the proposal. thanks Iain
diff --git a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst index ad0be51..ce6a4da 100644 --- a/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst +++ b/gcc/ada/doc/gnat_rm/interfacing_to_other_languages.rst @@ -123,6 +123,12 @@ It is also possible to import a C++ exception using the following syntax: The ``External_Name`` is the name of the C++ RTTI symbol. You can then cover a specific C++ exception in an exception handler. +RTTI symbols undergo C++ name mangling, which can make for identifiers +that are inconvenient to use. An alias with a mnemonic name can be +introduced by adding attribute ``exalias`` to the class that the RTTI +symbol refers to. + + .. _Interfacing_to_COBOL: Interfacing to COBOL diff --git a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst index b8729d0..2a13a24 100644 --- a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst +++ b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst @@ -4279,6 +4279,7 @@ and two public primitives to set and get the value of this attribute. public: virtual void Set_Age (int New_Age); virtual int Age (); + __attribute__ ((__exalias__ ("Ctor_For_Animal"))) // extra alias Animal() {Age_Count = 0;}; private: int Age_Count; @@ -4311,6 +4312,7 @@ both Carnivore and Domestic, that is: virtual int Number_Of_Teeth (); virtual void Set_Owner (char* Name); + __attribute__ ((__exalias__ ("Ctor_For_Dog"))) // mnemonic alias Dog(); // Constructor private: int Tooth_Count; @@ -4349,7 +4351,8 @@ how to import these C++ declarations from the Ada side: function New_Animal return Animal; pragma CPP_Constructor (New_Animal); - pragma Import (CPP, New_Animal, "_ZN6AnimalC1Ev"); + pragma Import (CPP, New_Animal, + "_ZN6AnimalC1Ev"); -- or "Ctor_For_Animal" type Dog is new Animal and Carnivore and Domestic with record Tooth_Count : Natural; @@ -4365,7 +4368,7 @@ how to import these C++ declarations from the Ada side: function New_Dog return Dog; pragma CPP_Constructor (New_Dog); - pragma Import (CPP, New_Dog, "_ZN3DogC2Ev"); + pragma Import (CPP, New_Dog, "Ctor_For_Dog"); -- or "_ZN3DogC1Ev" end Animals; Thanks to the compatibility between GNAT run-time structures and the C++ ABI, @@ -4382,12 +4385,13 @@ because the dispatch table associated with these tagged types will be built in the C++ side and therefore will not contain the predefined Ada primitives which Ada would otherwise expect. -As the reader can see there is no need to indicate the C++ mangled names -associated with each subprogram because it is assumed that all the calls to -these primitives will be dispatching calls. The only exception is the -constructor, which must be registered with the compiler by means of -``pragma CPP_Constructor`` and needs to provide its associated C++ -mangled name because the Ada compiler generates direct calls to it. +As the reader can see there is no need to indicate the C++ mangled +names (or extra aliases) associated with each subprogram because it is +assumed that all the calls to these primitives will be dispatching +calls. The only exception is the constructor, which must be registered +with the compiler by means of ``pragma CPP_Constructor`` and needs to +provide its associated C++ mangled name because the Ada compiler +generates direct calls to it. With the above packages we can now declare objects of type Dog on the Ada side and dispatch calls to the corresponding subprograms on the C++ side. We can diff --git a/gcc/attribs.c b/gcc/attribs.c index 71dae12..3768053 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "diagnostic-core.h" #include "attribs.h" +#include "cgraph.h" #include "stor-layout.h" #include "langhooks.h" #include "plugin.h" @@ -663,7 +664,8 @@ decl_attributes (tree *node, tree attributes, int flags, if (TYPE_P (*anode) && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE) - && TYPE_SIZE (*anode) != NULL_TREE) + && TYPE_SIZE (*anode) != NULL_TREE + && !is_attribute_p ("exalias", name)) { warning (OPT_Wattributes, "type attributes ignored after type is already defined"); continue; @@ -2076,6 +2078,68 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree fntype) } } +/* Create an exalias for DECL with linkage name ID. */ + +tree +create_exalias_decl (tree decl, tree id) +{ + tree name = get_identifier ("exalias"); + + if (symtab_node *sym_node = symtab_node::get_for_asmname (id)) + { + if ((sym_node->analyzed + ? sym_node->get_alias_target ()->decl + : sym_node->alias_target) == decl) + return sym_node->decl; + + error_at (DECL_SOURCE_LOCATION (decl), + "duplicate symbol name %qE in %qE attribute of %qD", + id, name, decl); + inform (DECL_SOURCE_LOCATION (sym_node->decl), + "already used by %qD", sym_node->decl); + } + + tree clone = copy_node (decl); + DECL_ATTRIBUTES (clone) = remove_attribute ("exalias", + DECL_ATTRIBUTES (decl)); + SET_DECL_ASSEMBLER_NAME (clone, id); + TREE_USED (id) = 1; + TREE_USED (clone) = 1; + DECL_PRESERVE_P (clone) = 1; + DECL_EXTERNAL (clone) = 0; + TREE_STATIC (clone) = 1; + + if (VAR_P (clone)) + { + DECL_READ_P (clone) = 1; + varpool_node::create_extra_name_alias (clone, decl); + } + else + { + cgraph_node::create_same_body_alias (clone, decl); + } + + return clone; +} + +/* Create all exaliases requested in DECL's attributes. */ + +void +create_exalias_decls (tree decl) +{ + if (!decl_in_symtab_p (decl) + || !symtab_node::get (decl)) + return; + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (decl)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + + create_exalias_decl (decl, id); + } +} + #if CHECKING_P diff --git a/gcc/attribs.h b/gcc/attribs.h index dea0b6c..1ba56ca 100644 --- a/gcc/attribs.h +++ b/gcc/attribs.h @@ -248,4 +248,11 @@ typedef hash_map<rdwr_access_hash, attr_access> rdwr_map; extern void init_attr_rdwr_indices (rdwr_map *, tree); +extern tree create_exalias_decl (tree, tree); +extern void create_exalias_decls (tree); + +#define FOR_EACH_EXALIAS(exalias, attrs) \ + for (tree exalias = lookup_attribute ("exalias", (attrs)); exalias; \ + exalias = lookup_attribute ("exalias", TREE_CHAIN (exalias))) + #endif // GCC_ATTRIBS_H diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c index c75b173..127eca6 100644 --- a/gcc/c-family/c-ada-spec.c +++ b/gcc/c-family/c-ada-spec.c @@ -1434,6 +1434,13 @@ pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type, static void pp_asm_name (pretty_printer *buffer, tree t) { + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (t)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + pp_string (buffer, TREE_STRING_POINTER (id)); + return; + } + tree name = DECL_ASSEMBLER_NAME (t); char *ada_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (name) + 1), *s; const char *ident = IDENTIFIER_POINTER (name); diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 3721483..c00de3f 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -99,7 +99,8 @@ static tree handle_noplt_attribute (tree *, tree, tree, int, bool *) ; static tree handle_alias_ifunc_attribute (bool, tree *, tree, tree, bool *); static tree handle_ifunc_attribute (tree *, tree, tree, int, bool *); static tree handle_alias_attribute (tree *, tree, tree, int, bool *); -static tree handle_weakref_attribute (tree *, tree, tree, int, bool *) ; +static tree handle_weakref_attribute (tree *, tree, tree, int, bool *); +static tree handle_exalias_attribute (tree *, tree, tree, int, bool *); static tree handle_visibility_attribute (tree *, tree, tree, int, bool *); static tree handle_tls_model_attribute (tree *, tree, tree, int, @@ -333,6 +334,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_alias_attribute, NULL }, { "weakref", 0, 1, true, false, false, false, handle_weakref_attribute, NULL }, + { "exalias", 1, 1, false, false, false, false, + handle_exalias_attribute, NULL }, { "no_instrument_function", 0, 0, true, false, false, false, handle_no_instrument_function_attribute, NULL }, @@ -2424,7 +2427,7 @@ handle_alias_ifunc_attribute (bool is_alias, tree *node, tree name, tree args, return NULL_TREE; } -/* Handle an "alias" or "ifunc" attribute; arguments as in +/* Handle an "ifunc" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -2434,7 +2437,7 @@ handle_ifunc_attribute (tree *node, tree name, tree args, return handle_alias_ifunc_attribute (false, node, name, args, no_add_attrs); } -/* Handle an "alias" or "ifunc" attribute; arguments as in +/* Handle an "alias" attribute; arguments as in struct attribute_spec.handler. */ static tree @@ -2444,6 +2447,29 @@ handle_alias_attribute (tree *node, tree name, tree args, return handle_alias_ifunc_attribute (true, node, name, args, no_add_attrs); } +/* Handle an "exalias" attribute; arguments as in struct + attribute_spec.handler. */ + +static tree +handle_exalias_attribute (tree *pnode, tree name, tree args, + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree node = *pnode; + + *no_add_attrs = true; + + if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) + error ("%qE attribute argument not a string", name); + else if (decl_in_symtab_p (node)) + *no_add_attrs = false; + else if (TYPE_P (node) && c_dialect_cxx ()) + *no_add_attrs = false; + else + return error_mark_node; + + return NULL_TREE; +} + /* Handle the "copy" attribute NAME by copying the set of attributes from the symbol referenced by ARGS to the declaration of *NODE. */ @@ -2571,6 +2597,7 @@ handle_copy_attribute (tree *node, tree name, tree args, tree atname = get_attribute_name (at); if (is_attribute_p ("alias", atname) || is_attribute_p ("always_inline", atname) + || is_attribute_p ("exalias", atname) || is_attribute_p ("gnu_inline", atname) || is_attribute_p ("ifunc", atname) || is_attribute_p ("noinline", atname) diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 5d6b504..79a3de1 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2942,6 +2942,8 @@ duplicate_decls (tree newdecl, tree olddecl) merge_decls (newdecl, olddecl, newtype, oldtype); + symtab_node::remap_exalias_target (newdecl, olddecl); + /* The NEWDECL will no longer be needed. Before releasing the node, be sure to remove function from symbol diff --git a/gcc/cgraph.c b/gcc/cgraph.c index c0b4579..a0121a0 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -524,6 +524,9 @@ cgraph_node::create (tree decl) node->next_nested = node->origin->nested; node->origin->nested = node; } + + create_exalias_decls (decl); + return node; } diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 0211f08..ab5bda5 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -319,6 +319,10 @@ public: /* Return node that alias is aliasing. */ inline symtab_node *get_alias_target (void); + /* Remap exalias nodes recorded as aliasing REPLACED to alias + REPLACEMENT instead. */ + static void remap_exalias_target (tree replaced, tree replacement); + /* Set section for symbol and its aliases. */ void set_section (const char *section); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 0b1009d..c96f720 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -1157,7 +1157,7 @@ analyze_functions (bool first_time) C++ FE is confused about the COMDAT groups being right. */ if (symtab->cpp_implicit_aliases_done) FOR_EACH_SYMBOL (node) - if (node->cpp_implicit_alias) + if (node->cpp_implicit_alias && node->analyzed) node->fixup_same_cpp_alias_visibility (node->get_alias_target ()); build_type_inheritance_graph (); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index b39bdaa..7e8f35f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4831,6 +4831,58 @@ copy_fndecl_with_name (tree fn, tree name, tree_code code, /* Create the RTL for this function. */ SET_DECL_RTL (clone, NULL); + + if (code == ERROR_MARK) + { + bool found = false; + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (clone)) + { + found = true; + break; + } + + if (found + && (name == complete_ctor_identifier + || name == complete_dtor_identifier)) + { + /* Reuse the exalias decls created for the primary cdtor decl. */ + symtab_node::remap_exalias_target (fn, clone); + } + else if (found) + { + const char *suf; + + if (name == base_ctor_identifier + || name == base_dtor_identifier) + suf = "_Base"; + else if (name == deleting_dtor_identifier) + suf = "_Del"; + else + gcc_unreachable (); + + size_t xlen = strlen (suf); + + DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (clone)); + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (clone)) + { + TREE_VALUE (exalias) = copy_list (TREE_VALUE (exalias)); + /* Append suf to the exalias name. */ + tree str = TREE_VALUE (TREE_VALUE (exalias)); + char *symname = concat (TREE_STRING_POINTER (str), suf, NULL); + str = build_string (TREE_STRING_LENGTH (str) + xlen, symname); + TREE_VALUE (TREE_VALUE (exalias)) = str; + free (symname); + } + + if (symtab_node::get (clone)) + create_exalias_decls (clone); + } + } + else + DECL_ATTRIBUTES (clone) + = remove_attribute ("exalias", DECL_ATTRIBUTES (clone)); + rest_of_decl_compilation (clone, namespace_bindings_p (), at_eof); return clone; @@ -4928,6 +4980,9 @@ build_cdtor_clones (tree fn, bool needs_vtt_parm_p, bool omit_inherited_parms_p) count += 2; } + DECL_ATTRIBUTES (fn) + = remove_attribute ("exalias", DECL_ATTRIBUTES (fn)); + return count; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fc54e6b..9ff45e0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6601,6 +6601,7 @@ extern tree build_explicit_specifier (tree, tsubst_flags_t); extern void do_push_parm_decls (tree, tree, tree *); /* in decl2.c */ +extern void update_exalias_interface (tree); extern void record_mangling (tree, bool); extern void overwrite_mangling (tree, tree); extern void note_mangling_alias (tree, tree); @@ -7043,6 +7044,7 @@ extern tree build_dynamic_cast (location_t, tree, tree, tsubst_flags_t); extern void emit_support_tinfos (void); extern bool emit_tinfo_decl (tree); +extern void update_tinfo_exalias (tree); /* in search.c */ extern bool accessible_base_p (tree, tree, bool); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a68bbe0..c1afde1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2899,6 +2899,8 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) && TREE_STATIC (olddecl)))) make_decl_rtl (olddecl); + symtab_node::remap_exalias_target (newdecl, olddecl); + /* The NEWDECL will no longer be needed. Because every out-of-class declaration of a member results in a call to duplicate_decls, freeing these nodes represents in a significant savings. @@ -9823,6 +9825,7 @@ grokfndecl (tree ctype, { cplus_decl_attributes (&decl, *attrlist, 0); *attrlist = NULL_TREE; + create_exalias_decls (decl); } /* Check main's type after attributes have been applied. */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 33c8377..d020e95 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1601,6 +1601,8 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) if (TREE_CODE (*decl) == TYPE_DECL) SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl)); + else if (TYPE_P (*decl) && attributes) + update_tinfo_exalias (*decl); /* Propagate deprecation out to the template. */ if (TREE_DEPRECATED (*decl)) @@ -1951,6 +1953,47 @@ adjust_var_decl_tls_model (tree decl) set_decl_tls_model (decl, decl_default_tls_model (decl)); } +/* Copy externalness and linkage from DECL to DEST. */ + +static void +copy_interface (tree dest, tree decl) +{ + TREE_PUBLIC (dest) = TREE_PUBLIC (decl); + TREE_STATIC (dest) = TREE_STATIC (decl); + DECL_COMMON (dest) = DECL_COMMON (decl); + DECL_COMDAT (dest) = DECL_COMDAT (decl); + DECL_WEAK (dest) = DECL_WEAK (decl); + DECL_EXTERNAL (dest) = DECL_EXTERNAL (decl); + if (DECL_LANG_SPECIFIC (dest) && DECL_LANG_SPECIFIC (decl)) + DECL_NOT_REALLY_EXTERN (dest) = DECL_NOT_REALLY_EXTERN (decl); + DECL_INTERFACE_KNOWN (dest) = DECL_INTERFACE_KNOWN (decl); + DECL_VISIBILITY (dest) = DECL_VISIBILITY (decl); + DECL_VISIBILITY_SPECIFIED (dest) = DECL_VISIBILITY_SPECIFIED (decl); +} + +/* Propagate linkage changes to exaliases. */ + +void +update_exalias_interface (tree decl) +{ + if (!decl_in_symtab_p (decl) + || !symtab_node::get (decl)) + return; + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (decl)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + symtab_node *sym_node = symtab_node::get_for_asmname (id); + + if (sym_node + && (sym_node->analyzed + ? sym_node->get_alias_target ()->decl + : sym_node->alias_target) == decl) + copy_interface (sym_node->decl, decl); + } +} + /* Set DECL up to have the closest approximation of "initialized common" linkage available. */ @@ -2747,6 +2790,8 @@ determine_visibility (tree decl) translation unit, we can make the type internal. */ constrain_visibility (decl, VISIBILITY_ANON, false); + update_exalias_interface (decl); + /* If visibility changed and DECL already has DECL_RTL, ensure symbol flags are updated. */ if ((DECL_VISIBILITY (decl) != orig_visibility @@ -3013,6 +3058,8 @@ tentative_decl_linkage (tree decl) else if (VAR_P (decl)) maybe_commonize_var (decl); } + + update_exalias_interface (decl); } /* DECL is a FUNCTION_DECL or VAR_DECL. If the object file linkage @@ -3247,6 +3294,8 @@ import_export_decl (tree decl) } DECL_INTERFACE_KNOWN (decl) = 1; + + update_exalias_interface (decl); } /* Return an expression that performs the destruction of DECL, which diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 9f30d90..26bdc25 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -22,9 +22,11 @@ along with GCC; see the file COPYING3. If not see #define INCLUDE_UNIQUE_PTR #include "system.h" #include "coretypes.h" +#include "target.h" #include "cp-tree.h" #include "timevar.h" #include "stringpool.h" +#include "cgraph.h" #include "print-tree.h" #include "attribs.h" #include "debug.h" @@ -2924,6 +2926,12 @@ set_local_extern_decl_linkage (tree decl, bool shadowed) different decl. */ TREE_PUBLIC (decl) = TREE_PUBLIC (*iter); + DECL_ATTRIBUTES (*iter) + = targetm.merge_decl_attributes (*iter, decl); + symtab_node::remap_exalias_target (decl, *iter); + DECL_ATTRIBUTES (decl) + = remove_attribute ("exalias", DECL_ATTRIBUTES (*iter)); + if (cp_function_chain->extern_decl_map == NULL) cp_function_chain->extern_decl_map = hash_table<cxx_int_tree_map_hasher>::create_ggc (20); diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index abdcd7f..62568d7 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -516,10 +516,15 @@ maybe_clone_body (tree fn) DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn); DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn); DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn); - DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); + /* We may have already copied them in copy_fndecl_with_name, + before dropping exaliases from fn. Don't overwrite it if so. */ + if (!DECL_ATTRIBUTES (clone)) + DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn); set_decl_section_name (clone, DECL_SECTION_NAME (fn)); + update_exalias_interface (clone); + /* Adjust the parameter names and locations. */ parm = DECL_ARGUMENTS (fn); clone_parm = DECL_ARGUMENTS (clone); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index d43248c..223c608 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -28,8 +28,10 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "intl.h" #include "stor-layout.h" +#include "attribs.h" #include "c-family/c-pragma.h" #include "gcc-rich-location.h" +#include "cgraph.h" /* C++ returns type information to the user in struct type_info objects. We also use type information to implement dynamic_cast and @@ -469,6 +471,18 @@ get_tinfo_decl (tree type) if (CLASS_TYPE_P (type)) CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d; + /* Copy exalias attributes from the type to the rtti obj decl. */ + tree *attrs = &DECL_ATTRIBUTES (d); + FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type)) + { + tree attr = tree_cons (TREE_PURPOSE (exalias), + TREE_VALUE (exalias), + *attrs); + *attrs = attr; + attrs = &TREE_CHAIN (attr); + } + create_exalias_decls (d); + /* Add decl to the global array of tinfo decls. */ vec_safe_push (unemitted_tinfo_decls, d); } @@ -476,6 +490,58 @@ get_tinfo_decl (tree type) return d; } +/* After modifying the attributes of TYPE, check whether tinfo was + already created and, if so, add to it any exalias attributes that + were not already present. */ + +void +update_tinfo_exalias (tree type) +{ + if (!TYPE_SIZE (type) || !CLASS_TYPE_P (type)) + return; + + tree d = CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)); + if (!d) + return; + + bool first = true; + symtab_node *node = NULL; + + tree *attrs = &DECL_ATTRIBUTES (d); + FOR_EACH_EXALIAS (exalias, TYPE_ATTRIBUTES (type)) + { + bool found = false; + FOR_EACH_EXALIAS (dexalias, *attrs) + if (TREE_VALUE (exalias) == TREE_VALUE (dexalias)) + { + found = true; + break; + } + + if (found) + continue; + + tree attr = tree_cons (TREE_PURPOSE (exalias), + TREE_VALUE (exalias), + *attrs); + *attrs = attr; + attrs = &TREE_CHAIN (attr); + + if (first) + { + first = false; + node = symtab_node::get (d); + } + + if (!node) + continue; + + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + create_exalias_decl (d, id); + } +} + /* Return a pointer to a type_info object describing TYPE, suitably cast to the language defined type. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 37a675a..0ba880f 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2882,6 +2882,39 @@ when using these attributes the problem is diagnosed earlier and with exact location of the call even in presence of inline functions or when not emitting debugging information. +@item exalias ("@var{name}") +@cindex @code{exalias} function attribute +The @code{exalias} attribute causes @var{name} to be emitted as an alias +to the definition. For instance, + +@smallexample +void f (uint64_t) __attribute__ ((__exalias__ ("f_u64"))); +void f (uint64_t) @{ /* @r{Do something.} */; @} +@end smallexample + +@noindent +defines @samp{f}, and outputs @samp{f_u64} as an alias for @samp{f}. +This is particularly useful when exporting C++ names for use in other +languages, or as an alias target, when machine-dependent types would +make mangled names harder to deal with. + +In the case of C++ constructors and destructors, in which a single +definition may output multiple symbols, the specified name is associated +with the variant that constructs or destructs a complete object. The +variant that applies to a base subobject gets a @code{_Base} suffix, and +the deleting destructor gets a @code{_Del} suffix. + +This attribute is silently ignored if @samp{f} is not defined in the +same translation unit, so that the attribute can be attached to forward +declarations. + +The name @samp{f_u64} is an assembly symbol name: it does not undergo +C++ name mangling, and it is not made visible in any scope in the source +language, but it can be named as an alias target. + +This attribute requires assembler and object file support, +and may not be available on all targets. + @item externally_visible @cindex @code{externally_visible} function attribute This attribute, attached to a global variable or function, nullifies @@ -6929,6 +6962,10 @@ align them on any target. The @code{aligned} attribute can also be used for functions (@pxref{Common Function Attributes}.) +@item exalias ("@var{name}") +@cindex @code{exalias} variable attribute +See @pxref{Common Function Attributes}. + @cindex @code{warn_if_not_aligned} variable attribute @item warn_if_not_aligned (@var{alignment}) This attribute specifies a threshold for the structure field, measured @@ -7067,6 +7104,21 @@ types (@pxref{Common Function Attributes}, The message attached to the attribute is affected by the setting of the @option{-fmessage-length} option. +@item exalias ("@var{name}") +@cindex @code{exalias} type attribute +The @code{exalias} attribute causes @var{name} to be emitted as an alias +to the definition of the C++ Run-Time Type Information (RTTI) +@code{std::type_info} object associated with the type. For instance, + +@smallexample +class foo __attribute__ ((__exalias__ ("TI_foo"))); +@end smallexample + +@noindent +arranges for @samp{TI_foo} to be defined as an alias to the RTTI object +for class @samp{foo}, once the class is defined and used in ways that +cause its RTTI object to be synthesized and output. + @item mode (@var{mode}) @cindex @code{mode} variable attribute This attribute specifies the data type for the declaration---whichever diff --git a/gcc/symtab.c b/gcc/symtab.c index d7dfbb6..0ea8532 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1874,6 +1874,42 @@ symtab_node::noninterposable_alias (symtab_node *node, void *data) return false; } +/* Remap exalias nodes recorded as aliasing REPLACED to alias + REPLACEMENT instead. */ + +void +symtab_node::remap_exalias_target (tree replaced, tree replacement) +{ + if (!decl_in_symtab_p (replacement) + || !symtab_node::get (replacement)) + return; + + FOR_EACH_EXALIAS (exalias, DECL_ATTRIBUTES (replaced)) + { + tree id = TREE_VALUE (TREE_VALUE (exalias)); + id = get_identifier (TREE_STRING_POINTER (id)); + + symtab_node *sym_node = symtab_node::get_for_asmname (id); + + if (!sym_node) + { + create_exalias_decl (replacement, id); + continue; + } + + gcc_assert (!sym_node->analyzed); + if (sym_node->alias_target != replaced) + continue; + + sym_node->definition = 0; + + if (VAR_P (replaced)) + varpool_node::create_extra_name_alias (sym_node->decl, replacement); + else + cgraph_node::create_same_body_alias (sym_node->decl, replacement); + } +} + /* If node cannot be overwriten by static or dynamic linker to point to different definition, return NODE. Otherwise look for alias with such property and if none exists, introduce new one. */ diff --git a/gcc/testsuite/c-c++-common/attr-weak-1.c b/gcc/testsuite/c-c++-common/attr-weak-1.c new file mode 100644 index 00000000..b11ef71 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-weak-1.c @@ -0,0 +1,19 @@ +/* { dg-do run { xfail *-*-* } } */ +/* { dg-require-effective-target weak_undefined } */ + +/* C++ wouldn't combine attributes from local declarations with a + namespace-scoped symbol. Now it does, but only if there is a + visible declaration. */ + +void foo () { + extern void __attribute__ ((__weak__)) undef_fn (void); + extern int __attribute__ ((__weak__)) undef_var; +} + +int main () { + extern void undef_fn (void); + extern int undef_var; + + if (&undef_fn || &undef_var) + __builtin_abort (); +} diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c new file mode 100644 index 00000000..3a471cc --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-1.c @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +extern int var_a __attribute__ ((__exalias__ ("FOOVAR_A"))); +int var_a = 1; + +void foo_a () __attribute__ ((__exalias__ ("FOOBAR_A"))); + +void +foo_a () +{ +} + + +int var_b; +extern int var_b __attribute__ ((__exalias__ ("FOOVAR_B"))); + +void +foo_b () +{ +} + +void foo_b () __attribute__ ((__exalias__ ("FOOBAR_B"))); + + +int var_c __attribute__ ((__exalias__ ("FOOVAR_C"))); + +void __attribute__ ((__exalias__ ("FOOBAR_C"))) +foo_c () +{ +} + + +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_B" } } */ +/* { dg-final { scan-assembler "FOOVAR_B" } } */ +/* { dg-final { scan-assembler "FOOBAR_C" } } */ +/* { dg-final { scan-assembler "FOOVAR_C" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c new file mode 100644 index 00000000..a0fe686 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +struct s +{ + int mem __attribute__ ((__exalias__ ("MEMFOO"))); /* { dg-warning "attribute ignored" } */ +}; + +void foo() +{ + extern void bar () __attribute__ ((__exalias__ ("FOOBAR"))); + int var __attribute__ ((__exalias__ ("FOOVAR"))); /* { dg-warning "attribute ignored" } */ +} diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c new file mode 100644 index 00000000..d94b618 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-3.c @@ -0,0 +1,41 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +int var_a = 1; + +void +foo_a () +{ + extern int var_a __attribute__ ((__exalias__ ("FOOVAR_A"))); + void foo_a () __attribute__ ((__exalias__ ("FOOBAR_A"))); +} + +#if __cplusplus +/* Without this declaration before the local declaration below, the + attributes of the local declaration do not get propagated to the + (global) namespace scope. */ +extern int var_b; +#endif + +void +foo_b () +{ + extern int var_b __attribute__ ((__exalias__ ("FOOVAR_B"))); +} + +int var_b; + +void __attribute__ ((__exalias__ ("FOOBAR_C"))) +foo_c () +{ + void foo_b () __attribute__ ((__exalias__ ("FOOBAR_B"))); + /* Another exalias for var_b. */ + extern int var_b __attribute__ ((__exalias__ ("FOOVAR_C"))); +} + +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_B" } } */ +/* { dg-final { scan-assembler "FOOVAR_B" } } */ +/* { dg-final { scan-assembler "FOOBAR_C" } } */ +/* { dg-final { scan-assembler "FOOVAR_C" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c b/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c new file mode 100644 index 00000000..6320d1a4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/attr-exalias-4.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-require-alias "" } */ + +int var_a __attribute__ ((__exalias__ ("FOOVAR_A"))) = 42; + +int __attribute__ ((__exalias__ ("FOOBAR_A"))) +foo_a (int p) +{ + return p; +} + +extern int __attribute__ ((__alias__ (("FOOVAR_A")))) var_b; +extern int __attribute__ ((__alias__ (("FOOBAR_A")))) foo_b (int p); + +int +foo_c () +{ + return foo_b (var_b); +} + +int +main () +{ + if (foo_c () != 42) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-1.C b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C new file mode 100644 index 00000000..ac355f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-1.C @@ -0,0 +1,70 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_A"))); + __attribute__ ((__exalias__ ("FOOCTR_A"))) foo (); + void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar (); + virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo() {} +}; + +int foo::var = 1; + +foo::foo () {} + +void foo::bar () {} + +namespace b { + class __attribute__ ((__exalias__ ("FOOCLS_B"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_B"))); + __attribute__ ((__exalias__ ("FOOCTR_B"))) foo (); + void __attribute__ ((__exalias__ ("FOOBAR_B"))) bar () {} + virtual __attribute__ ((__exalias__ ("FOODTR_B"))) ~foo() {} + }; + + int foo::var = 2; + + foo::foo () { + void (foo::*pbar)() = &foo::bar; + } +} + +namespace c { + namespace cd { + class __attribute__ ((__exalias__ ("FOOCLS_C"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_C"))); + __attribute__ ((__exalias__ ("FOOCTR_C"))) foo () { + void (foo::*pbar)() = &foo::bar; + } + void __attribute__ ((__exalias__ ("FOOBAR_C"))) bar () {} + virtual __attribute__ ((__exalias__ ("FOODTR_C"))) ~foo() {} + }; + + int foo::var = 3; + } +} + +/* { dg-final { scan-assembler "FOOCLS_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ +/* { dg-final { scan-assembler "FOOCLS_B" } } */ +/* { dg-final { scan-assembler "FOOBAR_B" } } */ +/* { dg-final { scan-assembler "FOOCTR_B" } } */ +/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_B" } } */ +/* { dg-final { scan-assembler "FOODTR_B_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_B_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_B" } } */ +/* { dg-final { scan-assembler "FOOCLS_C" } } */ +/* { dg-final { scan-assembler "FOOBAR_C" } } */ +/* { dg-final { scan-assembler "FOOCTR_C" } } */ +/* { dg-final { scan-assembler "FOOCTR_C_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_C" } } */ +/* { dg-final { scan-assembler "FOODTR_C_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_C_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_C" } } */ diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-2.C b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C new file mode 100644 index 00000000..266ee0c --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-2.C @@ -0,0 +1,26 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +namespace { + class __attribute__ ((__exalias__ ("FOOCLS_A"))) foo { + static int var __attribute__ ((__exalias__ ("FOOVAR_A"))); + __attribute__ ((__exalias__ ("FOOCTR_A"))) foo (); + virtual __attribute__ ((__exalias__ ("FOODTR_A"))) ~foo (); + void __attribute__ ((__exalias__ ("FOOBAR_A"))) bar (); + }; + + int foo::var = 3; + foo::foo () {} + foo::~foo () {} + void foo::bar () {} +} + +/* { dg-final { scan-assembler-not "\.globl" } } */ +/* { dg-final { scan-assembler "FOOCLS_A" } } */ +/* { dg-final { scan-assembler "FOOBAR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A" } } */ +/* { dg-final { scan-assembler "FOOCTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Base" } } */ +/* { dg-final { scan-assembler "FOODTR_A_Del" } } */ +/* { dg-final { scan-assembler "FOOVAR_A" } } */ diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-3.C b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C new file mode 100644 index 00000000..a81348a --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-3.C @@ -0,0 +1,83 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +// exalias can be applied to template function explicit instantiations. + +template <typename T> +void +fn(T) { +}; + +template void __attribute__ ((__exalias__ ("FOOFUN_UINT"))) fn<>(unsigned int); +template void __attribute__ ((__exalias__ ("FOOFUN_LONG"))) fn<>(long); + +template<> void __attribute__ ((__exalias__ ("FOOFUN_CHAR"))) fn<>(char) {} + + +template <typename T = void> +struct +foo { + virtual ~foo() {} + + virtual void virtfun() {} + + static void stfun() {} + void inlfun() {} +}; + +// Explicitly instantiate members before the enclosing class. + +template void +__attribute__ ((__exalias__ ("FOOCLS_CHAR_VIRT"))) foo<char>::virtfun(); + +template class __attribute__ ((__exalias__ ("FOOCLS_CHAR_TI"))) foo<char>; + +// Though they're only output if the enclosing class is. +template void +__attribute__ ((__exalias__ ("FOOCLS_LONG_VIRT"))) foo<long>::virtfun(); +extern +template class __attribute__ ((__exalias__ ("FOOCLS_LONG_TI_X"))) foo<long>; + + +template void +__attribute__ ((__exalias__ ("FOOCLS_VOID_ST"))) foo<void>::stfun(); + +template class __attribute__ ((__exalias__ ("FOOCLS_VOID_TI"))) foo<>; + + +extern +template class __attribute__ ((__exalias__ ("FOOCLS_SHORT_TI_X"))) foo<short>; + +template void +__attribute__ ((__exalias__ ("FOOCLS_SHORT_ST"))) foo<short>::stfun(); +template void +__attribute__ ((__exalias__ ("FOOCLS_SHORT_INL"))) foo<short>::inlfun(); + +template class __attribute__ ((__exalias__ ("FOOCLS_SHORT_TI_D"))) foo<short>; + +// Explicit specializations work too. + +template <> +struct __attribute__ ((__exalias__ ("FOOCLS_INT_TI"))) +foo<int> +{ + virtual ~foo() {} + virtual void __attribute__ ((__exalias__ ("FOOCLS_INT_VIRT"))) virtfun() {} +}; + +/* { dg-final { scan-assembler "FOOFUN_UINT" } } */ +/* { dg-final { scan-assembler "FOOFUN_LONG" } } */ +/* { dg-final { scan-assembler "FOOFUN_CHAR" } } */ + +/* { dg-final { scan-assembler "FOOCLS_VOID_TI" } } */ +/* { dg-final { scan-assembler "FOOCLS_VOID_ST" } } */ +/* { dg-final { scan-assembler "FOOCLS_CHAR_TI" } } */ +/* { dg-final { scan-assembler "FOOCLS_CHAR_VIRT" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_TI_X" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_ST" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_INL" } } */ +/* { dg-final { scan-assembler "FOOCLS_SHORT_TI_D" } } */ +/* { dg-final { scan-assembler-not "FOOCLS_LONG_TI_X" } } */ +/* { dg-final { scan-assembler-not "FOOCLS_LONG_VIRT" } } */ +/* { dg-final { scan-assembler "FOOCLS_INT_TI" } } */ +/* { dg-final { scan-assembler "FOOCLS_INT_VIRT" } } */ diff --git a/gcc/testsuite/g++.dg/torture/attr-exalias-4.C b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C new file mode 100644 index 00000000..9623bef --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/attr-exalias-4.C @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-require-alias "" } */ + +template <typename T = void> +class +__attribute__ ((__exalias__ ("FOOCLS"))) +foo // { dg-error "duplicate|already" } +{ + virtual ~foo() {} + + template <typename U> + void + __attribute__ ((__exalias__ ("FOOTMF"))) + tmemfun () {} // { dg-error "duplicate|already" } +}; + +template <typename T> +void +__attribute__ ((__exalias__ ("FOOTFN"))) +fn(T) { // { dg-error "duplicate|already" } +}; + +template class foo<>; +template class foo<int>; +template void foo<>::tmemfun<void>(); +template void foo<int>::tmemfun<void>(); +template void fn<>(int); +template void fn<>(long); diff --git a/gcc/varpool.c b/gcc/varpool.c index 458cdf1..5f89662 100644 --- a/gcc/varpool.c +++ b/gcc/varpool.c @@ -162,6 +162,9 @@ varpool_node::get_create (tree decl) } node->register_symbol (); + + create_exalias_decls (decl); + return node; }