Index: docs/ItaniumMangleAbiTags.rst =================================================================== --- /dev/null +++ docs/ItaniumMangleAbiTags.rst @@ -0,0 +1,90 @@ +======== +Abi Tags +======== + +Introduction +============ + +This text tries to describe gcc semantic for mangling "abi_tag" attributes +described in https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html + +There is no guarantee the following rules are correct, complete or make sense +in any way as they were determined empirically by experiments with gcc5. + +Declaration +=========== + +Abi tags are declared in an abi_tag attribute and can be applied to a +function, variable, class or inline namespace declaration. The attribute takes +one or more strings (called tags); the order does not matter. + +See https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html for +details. + +Tags on an inline namespace are called "implicit tags", all other tags are +"explicit tags". + +Mangling +======== + +All tags that are "active" on a are emitted after the +, before or , and are part of +the same the is. + +They are mangled as: + + ::= * # sort by name + ::= B + +Example: + + __attribute__((abi_tag("test"))) + void Func(); + + gets mangled as: _Z4FuncB4testv (prettified as `Func[abi:test]()`) + +Active tags +=========== + +A namespace has never any active tags; for types (class / struct / union / +enum) the explicit tags are the active tags. + +For variables and functions the active tags are the explicit tags plus any +"required tags" which are not in the "available tags" set: + + derived-tags := (required-tags - available-tags) + active-tags := explicit-tags + derived-tags + +Required tags for a function +============================ + +If a function is used as a local scope for another name, and is part of +another function as local scope, it doesn't have any required tags. + +If a function is used as a local scope for a guard variable name, it doesn't +have any required tags. + +Otherwise the function requires any implicit or explicit tag used in the name +for the return type. + +Required tags for a variable +============================ + +A variable requires any implicit or explicit tag used in its type. + +Available tags +============== + +All tags used in the prefix and in the template arguments for a name are +available; for functions also all tags from the (which +might include the return type for template functions) are available. + +For s all active tags used in the local part () are available, but not implicit tags which were not active! + +Implicit and explicit tags used in the for a function (as +in the type of a cast operator) are NOT available. + +Example: a cast operator to std::string (which is +std::__cxx11::basic_string<...>) will use 'cxx11' as active tag, as it is +required from the return type `std::string` but not available. Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -350,6 +350,14 @@ // Attributes begin here // +def AbiTag : Attr { + let Spellings = [GCC<"abi_tag">]; + let Args = [VariadicStringArgument<"Tags">]; + let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag, + "ExpectedStructClassVariableFunctionOrInlineNamespace">; + let Documentation = [AbiTagsDocs]; +} + def AddressSpace : TypeAttr { let Spellings = [GNU<"address_space">]; let Args = [IntArgument<"AddressSpace">]; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -1958,3 +1958,16 @@ The system will crash if the wrong handler is used. }]; } + +def AbiTagsDocs : Documentation { + let Content = [{ +The ``abi_tag`` attribute can be applied to a function, variable, class or +inline namespace declaration to modify mangled name of the entity. It allows +to distinguish different versions of the same entity but with different ABI +version supported. For example, newer version of a class could have more or less +data members and thus have different size. Using the ``abi_tag`` attribute it is +possible to have different mangled name for a global variable of the class type. +Therefor old code could keep using old manged name and new code will use new +mangled name with tags. + }]; +} Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2461,7 +2461,8 @@ "variables, functions and classes|Objective-C protocols|" "functions and global variables|structs, unions, and typedefs|structs and typedefs|" "interface or protocol declarations|kernel functions|non-K&R-style functions|" - "variables, enums, fields and typedefs}1">, + "variables, enums, fields and typedefs|" + "structs, classes, variables, functions and inline namespaces}1">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< @@ -4171,6 +4172,13 @@ def err_redefinition_extern_inline : Error< "redefinition of a 'extern inline' function %0 is not supported in " "%select{C99 mode|C++}1">; +def warn_attr_abi_tag_namespace : Warning< + "'abi_tag' attribute on %select{non-inline|anonymous}0 namespace ignored">, + InGroup; +def err_abi_tag_on_redeclaration : Error< + "cannot add 'abi_tag' attribute in redeclaration">; +def err_new_abi_tag_on_redeclaration : Error< + "'abi_tag' %0 missing in original declaration">; def note_deleted_dtor_no_operator_delete : Note< "virtual destructor requires an unambiguous, accessible 'operator delete'">; Index: include/clang/Sema/AttributeList.h =================================================================== --- include/clang/Sema/AttributeList.h +++ include/clang/Sema/AttributeList.h @@ -876,7 +876,8 @@ ExpectedObjectiveCInterfaceOrProtocol, ExpectedKernelFunction, ExpectedFunctionWithProtoType, - ExpectedVariableEnumFieldOrTypedef + ExpectedVariableEnumFieldOrTypedef, + ExpectedStructClassVariableFunctionOrInlineNamespace }; } // end namespace clang Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -2398,6 +2398,24 @@ } } + // Re-declaration cannot add abi_tag's. + if (const auto *NewAbiTagAttr = New->getAttr()) { + if (const auto *OldAbiTagAttr = Old->getAttr()) { + for (const auto &NewTag : NewAbiTagAttr->tags()) { + if (std::find(OldAbiTagAttr->tags_begin(), OldAbiTagAttr->tags_end(), + NewTag) == OldAbiTagAttr->tags_end()) { + Diag(NewAbiTagAttr->getLocation(), + diag::err_new_abi_tag_on_redeclaration) + << NewTag; + Diag(OldAbiTagAttr->getLocation(), diag::note_previous_declaration); + } + } + } else { + Diag(NewAbiTagAttr->getLocation(), diag::err_abi_tag_on_redeclaration); + Diag(Old->getLocation(), diag::note_previous_declaration); + } + } + if (!Old->hasAttrs()) return; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4493,6 +4493,42 @@ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } +static void handleAbiTagAttr(Sema &S, Decl *D, const AttributeList &Attr) { + SmallVector Tags; + for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + StringRef Tag; + if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag)) + return; + Tags.push_back(Tag); + } + + if (const auto *NS = dyn_cast(D)) { + if (!NS->isInline()) { + S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; + return; + } + if (NS->isAnonymousNamespace()) { + S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; + return; + } + if (Attr.getNumArgs() == 0) + Tags.push_back(NS->getName()); + } else if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // Store tags sorted and without duplicates. + std::sort(Tags.begin(), Tags.end()); + Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); + + D->addAttr(::new (S.Context) + AbiTagAttr(Attr.getRange(), S.Context, Tags.data(), Tags.size(), + Attr.getAttributeSpellingListIndex())); + + // FIXME: remove this warning as soon as mangled part is ready. + S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored) + << Attr.getName(); +} + static void handleARMInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check the attribute arguments. @@ -5500,6 +5536,9 @@ case AttributeList::AT_Thread: handleDeclspecThreadAttr(S, D, Attr); break; + case AttributeList::AT_AbiTag: + handleAbiTagAttr(S, D, Attr); + break; // Thread safety attributes: case AttributeList::AT_AssertExclusiveLock: Index: test/SemaCXX/attr-abi-tag-syntax.cpp =================================================================== --- /dev/null +++ test/SemaCXX/attr-abi-tag-syntax.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s + +namespace N1 { + +namespace __attribute__((__abi_tag__)) {} +// expected-warning@-1 {{'abi_tag' attribute on non-inline namespace ignored}} + +namespace N __attribute__((__abi_tag__)) {} +// expected-warning@-1 {{'abi_tag' attribute on non-inline namespace ignored}} + +} // namespace N1 + +namespace N2 { + +inline namespace __attribute__((__abi_tag__)) {} +// expected-warning@-1 {{'abi_tag' attribute on anonymous namespace ignored}} + +inline namespace N __attribute__((__abi_tag__)) {} +// FIXME: remove this warning as soon as attribute fully supported. +// expected-warning@-2 {{'__abi_tag__' attribute ignored}} + +} // namespcace N2 + +__attribute__((abi_tag("B", "A"))) extern int a1; +// FIXME: remove this warning as soon as attribute fully supported. +// expected-warning@-2 {{'abi_tag' attribute ignored}} + +__attribute__((abi_tag("A", "B"))) extern int a1; +// expected-note@-1 {{previous declaration is here}} +// FIXME: remove this warning as soon as attribute fully supported. +// expected-warning@-3 {{'abi_tag' attribute ignored}} + +__attribute__((abi_tag("A", "C"))) extern int a1; +// expected-error@-1 {{'abi_tag' C missing in original declaration}} +// FIXME: remove this warning as soon as attribute fully supported. +// expected-warning@-3 {{'abi_tag' attribute ignored}} + +extern int a2; +// expected-note@-1 {{previous declaration is here}} +__attribute__((abi_tag("A")))extern int a2; +// expected-error@-1 {{cannot add 'abi_tag' attribute in redeclaration}} +// FIXME: remove this warning as soon as attribute fully supported. +// expected-warning@-3 {{'abi_tag' attribute ignored}}