Skip to content

Instantly share code, notes, and snippets.

@stbuehler
Last active December 14, 2015 16:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stbuehler/2b83e35838643b3b3c46 to your computer and use it in GitHub Desktop.
Save stbuehler/2b83e35838643b3b3c46 to your computer and use it in GitHub Desktop.
clang abi-tag support.patch
Author: Stefan Bühler <stbuehler@web.de>
add gcc abi_tag support
- parse abi_tag attribute
- emit abi tags in name Itanium Mangling (but not for namespaces)
- for functions the abi tags from the return type need to be added
to the mangling of the function name, as long as they are not part of
the mangled function name otherwise (as tag on any involved namespace
or parameter type). Use nested "null" mangling of the signature to
gather these tags in advance.
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 4b8a7b7..8f8b9ba 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -344,6 +344,14 @@ class IgnoredAttr : Attr {
// Attributes begin here
//
+def AbiTag : Attr {
+ let Spellings = [GCC<"abi_tag">];
+ let Args = [VariadicStringArgument<"Tags">];
+ let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag,
+ "ExpectedStructClassVariableFunctionMethodOrInlineNamespace">;
+ let Documentation = [Undocumented];
+}
+
def AddressSpace : TypeAttr {
let Spellings = [GNU<"address_space">];
let Args = [IntArgument<"AddressSpace">];
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 6ac5748..17f46fa 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2336,7 +2336,8 @@ def warn_attribute_wrong_decl_type : Warning<
"Objective-C instance methods|init methods of interface or class extension declarations|"
"variables, functions and classes|Objective-C protocols|"
"functions and global variables|structs, unions, and typedefs|structs and typedefs|"
- "interface or protocol declarations|kernel functions}1">,
+ "interface or protocol declarations|kernel functions|"
+ "structs, classes, variables, functions, methods and inline namespaces}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
def warn_type_attribute_wrong_type : Warning<
@@ -4013,6 +4014,13 @@ def err_definition_of_explicitly_defaulted_member : Error<
def err_redefinition_extern_inline : Error<
"redefinition of a 'extern inline' function %0 is not supported in "
"%select{C99 mode|C++}1">;
+def err_attr_abi_tag_only_on_inline_namespace :
+ Error<"abi_tag attribute only allowed on inline namespaces">;
+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'">;
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index ca456b2..c3f0841 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -852,7 +852,8 @@ enum AttributeDeclKind {
ExpectedStructOrUnionOrTypedef,
ExpectedStructOrTypedef,
ExpectedObjectiveCInterfaceOrProtocol,
- ExpectedKernelFunction
+ ExpectedKernelFunction,
+ ExpectedStructClassVariableFunctionMethodOrInlineNamespace
};
} // end namespace clang
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 3f40743..8d06307 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -214,6 +214,9 @@ public:
class CXXNameMangler {
ItaniumMangleContextImpl &Context;
raw_ostream &Out;
+ bool NullOut = false;
+ bool DisableAbiTags = false;
+ bool WorkaroundGCCAbiTagBug = false;
/// The "structor" is the top-level declaration being mangled, if
/// that's not a template specialization; otherwise it's the pattern
@@ -263,6 +266,148 @@ class CXXNameMangler {
} FunctionTypeDepth;
+ // abi_tag is a gcc attribute, taking one or more strings called "tags".
+ //
+ // the goal is to annotage against which version of a library an object was
+ // build and to be able to provide backwards compatibility ("dual abi").
+ //
+ // for this the emitted mangled names have to be different, while you don't
+ // want the user to have to use different names in the source.
+ //
+ // the abi_tag can be present on Struct, Var and Function declarations as
+ // "explicit" tag, and on inline Namespace as "implicit" tag. Explicit tags
+ // are always emitted after the unqualified name, and (implicit) tags on
+ // namespace are not.
+ //
+ // For functions and variables there is a set of "implicitly available"
+ // tags. These tags are: all tags from the namespace/structs the name is
+ // embedded in, all tags from any template arguments of the name, and, for
+ // functions, alls tags used anywhere in the <bare-function-type> (i.e.
+ // parameters and sometimes the return type).
+ //
+ // For functions this is basically the list of all tags from the signature
+ // without the unqualified name and usually without the return type of the
+ // function. In `operator Type()` Type is NOT part of that list, as it is
+ // part of the unqualified name!
+ //
+ // Now all tags from the function return type/variable type which are not
+ // "implicitly available" must be added to the explicit list of tags, and
+ // are emitted after the unqualified name.
+ //
+ // Example:
+ // namespace std {
+ // inline namespace __cxx11 __attribute__((__abi_tag__("cxx11"))) { }
+ // inline namespace __cxx11 {
+ // struct string { };
+ // }
+ // }
+ //
+ // std::string foo(); // needs abi tag "cxx11" on foo
+ // std::string foo(std::string); // does NOT need abi tag "cxx11" on foo
+ // __attribute__((__abi_tag__("cxx11")))
+ // std::string foo2(std::string); // emit abi tag "cxx11" on foo anyway
+ //
+ // The tags are sorted by name before emitting, and are serialized as
+ // <abitag> ::= B <"tag" source-name>
+
+ typedef SmallVector<StringRef, 4> AbiTagList;
+
+ // state to gather all implicit and explicit tags used in a mangled name.
+ // must always have an instance of this while emitting any name to keep
+ // track.
+ //
+ // TODO(abitags): how to handle substituted names? they should add the tags used in
+ // the substitution to the list of available tags.
+ class AbiTagState final {
+ public:
+ //! all abi tags used implicitly or explicitly
+ std::set<StringRef> UsedAbiTags;
+
+ AbiTagState* &LinkHead;
+ AbiTagState *Parent{nullptr};
+
+ bool LinkActive{false};
+
+ explicit AbiTagState(AbiTagState* &linkHead)
+ : LinkHead(linkHead) {
+ Parent = LinkHead;
+ LinkHead = this;
+ LinkActive = true;
+ }
+
+ // no copy, no move
+ AbiTagState(AbiTagState const&) = delete;
+ AbiTagState& operator=(AbiTagState const&) = delete;
+
+ ~AbiTagState() {
+ pop();
+ }
+
+ void pop() {
+ if (!LinkActive) return;
+
+ assert(LinkHead == this && "abi tag link head must point to us on destruction");
+ LinkActive = false;
+ if (Parent) {
+ Parent->UsedAbiTags.insert(UsedAbiTags.begin(), UsedAbiTags.end());
+ }
+ LinkHead = Parent;
+ }
+
+ void write(raw_ostream &Out, const NamedDecl *ND, const AbiTagList *AdditionalAbiTags) {
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
+ if (dyn_cast<FunctionDecl>(ND) || dyn_cast<VarDecl>(ND)) {
+ // assert(AdditionalAbiTags && "function and variables need a list of additional abi tags");
+ } else {
+ assert(!AdditionalAbiTags && "only function and variables need a list of additional abi tags");
+ if (const auto* NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (const auto* AbiTag = NS->getAttr<AbiTagAttr>()) {
+ for (const auto& Tag: AbiTag->tags()) {
+ UsedAbiTags.insert(Tag);
+ }
+ }
+ // don't emit abi tags for namespaces
+ return;
+ }
+ }
+
+ AbiTagList TagList;
+ if (const auto* AbiTag = ND->getAttr<AbiTagAttr>()) {
+ for (const auto& Tag: AbiTag->tags()) {
+ UsedAbiTags.insert(Tag);
+ // AbiTag->tags() is sorted and has no duplicates
+ TagList.push_back(Tag);
+ }
+ }
+
+ if (AdditionalAbiTags) {
+ for (const auto& Tag: *AdditionalAbiTags) {
+ UsedAbiTags.insert(Tag);
+ if (std::find(TagList.begin(), TagList.end(), Tag) == TagList.end()) {
+ // don't insert duplicates
+ TagList.push_back(Tag);
+ }
+ }
+ // AbiTag->tags() are already sorted; only add if we had additional tags
+ std::sort(TagList.begin(), TagList.end());
+ }
+
+ writeSortedUniqueAbiTags(Out, TagList);
+ }
+
+ protected:
+ template<typename TagList>
+ void writeSortedUniqueAbiTags(raw_ostream &Out, TagList const& AbiTags) {
+ for (const auto& Tag: AbiTags) {
+ Out << "B";
+ Out << Tag.size();
+ Out << Tag;
+ }
+ }
+ } *AbiTags = nullptr;
+ AbiTagState AbiTagsRoot{AbiTags};
+
llvm::DenseMap<uintptr_t, unsigned> Substitutions;
ASTContext &getASTContext() const { return Context.getASTContext(); }
@@ -285,6 +430,10 @@ public:
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
SeqID(0) { }
+ CXXNameMangler(CXXNameMangler &Outer, llvm::raw_null_ostream &Out_)
+ : Context(Outer.Context), Out(Out_), NullOut(true), Structor(Outer.Structor), StructorType(Outer.StructorType),
+ SeqID(Outer.SeqID) { }
+
#if MANGLE_CHECKER
~CXXNameMangler() {
if (Out.str()[0] == '\01')
@@ -298,18 +447,21 @@ public:
#endif
raw_ostream &getStream() { return Out; }
+ void disableAbiTags() { DisableAbiTags = true; }
+
void mangle(const NamedDecl *D);
void mangleCallOffset(int64_t NonVirtual, int64_t Virtual);
void mangleNumber(const llvm::APSInt &I);
void mangleNumber(int64_t Number);
void mangleFloat(const llvm::APFloat &F);
- void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleFunctionEncoding(const FunctionDecl *FD, bool ExcludeUnqualifiedName = false);
void mangleSeqID(unsigned SeqID);
- void mangleName(const NamedDecl *ND);
+ void mangleName(const NamedDecl *ND, bool ExcludeUnqualifiedName = false);
void mangleType(QualType T);
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
private:
+ void writeAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags = nullptr);
bool mangleSubstitution(const NamedDecl *ND);
bool mangleSubstitution(QualType T);
@@ -336,31 +488,49 @@ private:
DeclarationName name,
unsigned KnownArity = UnknownArity);
- void mangleName(const TemplateDecl *TD,
+ void mangleFunctionEncodingBareType(const FunctionDecl *FD);
+
+ void mangleNameWithAbiTags(const NamedDecl *ND,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName);
+ void mangleTemplateName(const TemplateDecl *TD,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleUnqualifiedName(const NamedDecl *ND) {
- mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity);
+ void mangleUnqualifiedName(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags) {
+ mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity, AdditionalAbiTags);
}
void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name,
- unsigned KnownArity);
- void mangleUnscopedName(const NamedDecl *ND);
- void mangleUnscopedTemplateName(const TemplateDecl *ND);
- void mangleUnscopedTemplateName(TemplateName);
+ unsigned KnownArity, const AbiTagList *AdditionalAbiTags);
+ void mangleUnscopedName(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags);
+ void mangleUnscopedTemplateName(const TemplateDecl *ND,
+ const AbiTagList *AdditionalAbiTags);
+ void mangleUnscopedTemplateName(TemplateName,
+ const AbiTagList *AdditionalAbiTags);
void mangleSourceName(const IdentifierInfo *II);
- void mangleLocalName(const Decl *D);
+ void mangleLocalName(const Decl *D,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName);
void mangleBlockForPrefix(const BlockDecl *Block);
void mangleUnqualifiedBlock(const BlockDecl *Block);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
- bool NoFunction=false);
+ const AbiTagList *AdditionalAbiTags,
+ bool NoFunction,
+ bool ExcludeUnqualifiedName);
void mangleNestedName(const TemplateDecl *TD,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
void manglePrefix(NestedNameSpecifier *qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void manglePrefix(QualType type);
- void mangleTemplatePrefix(const TemplateDecl *ND, bool NoFunction=false);
+ void mangleTemplatePrefix(const TemplateDecl *ND,
+ const AbiTagList *AdditionalAbiTags,
+ bool NoFunction = false,
+ bool ExcludeUnqualifiedName = false);
void mangleTemplatePrefix(TemplateName Template);
bool mangleUnresolvedTypeOrSimpleId(QualType DestroyedType,
StringRef Prefix = "");
@@ -406,6 +576,10 @@ private:
void mangleTemplateParameter(unsigned Index);
void mangleFunctionParam(const ParmVarDecl *parm);
+
+ std::set<StringRef> getTagsFromPrefixAndTemplateArguments(const NamedDecl *ND);
+ AbiTagList makeAdditionalTagsForFunction(const FunctionDecl *FD);
+ AbiTagList makeAdditionalTagsForVariable(const VarDecl *VD);
};
}
@@ -456,6 +630,12 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
return true;
}
+void CXXNameMangler::writeAbiTags(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags) {
+ if (DisableAbiTags) return;
+ assert(AbiTags && "require AbiTagState");
+ if (AbiTags) AbiTags->write(Out, ND, AdditionalAbiTags);
+}
+
void CXXNameMangler::mangle(const NamedDecl *D) {
// <mangled-name> ::= _Z <encoding>
// ::= <data name>
@@ -471,14 +651,28 @@ void CXXNameMangler::mangle(const NamedDecl *D) {
mangleName(cast<FieldDecl>(D));
}
-void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
- // <encoding> ::= <function name> <bare-function-type>
- mangleName(FD);
-
+void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD, bool ExcludeUnqualifiedName) {
// Don't mangle in the type if this isn't a decl we should typically mangle.
- if (!Context.shouldMangleDeclName(FD))
+ if (!Context.shouldMangleDeclName(FD)) {
+ mangleNameWithAbiTags(FD, /* AdditionalAbiTags */ nullptr, ExcludeUnqualifiedName);
return;
+ }
+
+ // <encoding> ::= <function name> <bare-function-type>
+
+ if (ExcludeUnqualifiedName)
+ {
+ // running makeAdditionalTagsForFunction would loop, don't need it here anyway
+ mangleNameWithAbiTags(FD, /* AdditionalAbiTags */ nullptr, ExcludeUnqualifiedName);
+ } else {
+ AbiTagList AdditionalAbiTags = makeAdditionalTagsForFunction(FD);
+ mangleNameWithAbiTags(FD, &AdditionalAbiTags, ExcludeUnqualifiedName);
+ }
+
+ mangleFunctionEncodingBareType(FD);
+}
+void CXXNameMangler::mangleFunctionEncodingBareType(const FunctionDecl *FD) {
if (FD->hasAttr<EnableIfAttr>()) {
FunctionTypeDepthState Saved = FunctionTypeDepth.push();
Out << "Ua9enable_ifI";
@@ -524,8 +718,8 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
FD = PrimaryTemplate->getTemplatedDecl();
}
- mangleBareFunctionType(FD->getType()->getAs<FunctionType>(),
- MangleReturnType);
+ mangleBareFunctionType(FD->getType()->getAs<FunctionType>(),
+ MangleReturnType && !WorkaroundGCCAbiTagBug);
}
static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
@@ -582,7 +776,21 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return nullptr;
}
-void CXXNameMangler::mangleName(const NamedDecl *ND) {
+// must not be run from mangleLocalName for the <entity name> as it would loop otherwise.
+void CXXNameMangler::mangleName(const NamedDecl *ND, bool ExcludeUnqualifiedName) {
+ if (!ExcludeUnqualifiedName) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ AbiTagList VariableAdditionalAbiTags = makeAdditionalTagsForVariable(VD);
+ mangleNameWithAbiTags(VD, &VariableAdditionalAbiTags, ExcludeUnqualifiedName);
+ return;
+ }
+ }
+ mangleNameWithAbiTags(ND, nullptr, ExcludeUnqualifiedName);
+}
+
+void CXXNameMangler::mangleNameWithAbiTags(const NamedDecl *ND,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName) {
// <name> ::= <nested-name>
// ::= <unscoped-name>
// ::= <unscoped-template-name> <template-args>
@@ -598,7 +806,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
- mangleLocalName(ND);
+ mangleLocalName(ND, AdditionalAbiTags, ExcludeUnqualifiedName);
return;
}
@@ -608,76 +816,88 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleUnscopedTemplateName(TD);
+ if (!ExcludeUnqualifiedName)
+ mangleUnscopedTemplateName(TD, AdditionalAbiTags);
mangleTemplateArgs(*TemplateArgs);
return;
}
- mangleUnscopedName(ND);
+ if (!ExcludeUnqualifiedName)
+ mangleUnscopedName(ND, AdditionalAbiTags);
return;
}
if (isLocalContainerContext(DC)) {
- mangleLocalName(ND);
+ mangleLocalName(ND, AdditionalAbiTags, ExcludeUnqualifiedName);
return;
}
- mangleNestedName(ND, DC);
+ mangleNestedName(ND, DC, AdditionalAbiTags, /* NoFunction */ false, ExcludeUnqualifiedName);
}
-void CXXNameMangler::mangleName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+
+void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD));
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
- mangleUnscopedTemplateName(TD);
+ if (!ExcludeUnqualifiedName)
+ mangleUnscopedTemplateName(TD, AdditionalAbiTags);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
} else {
- mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
+ mangleNestedName(TD, AdditionalAbiTags, ExcludeUnqualifiedName, TemplateArgs, NumTemplateArgs);
}
}
-void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
+void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND, const AbiTagList *AdditionalAbiTags) {
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
if (isStdNamespace(IgnoreLinkageSpecDecls(getEffectiveDeclContext(ND))))
Out << "St";
- mangleUnqualifiedName(ND);
+ mangleUnqualifiedName(ND, AdditionalAbiTags);
}
-void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
+void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND,
+ const AbiTagList *AdditionalAbiTags) {
// <unscoped-template-name> ::= <unscoped-name>
// ::= <substitution>
if (mangleSubstitution(ND))
return;
// <template-template-param> ::= <template-param>
- if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND))
+ if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ assert(!AdditionalAbiTags && "template template param cannot have abi tags"); // TODO(abitags)
mangleTemplateParameter(TTP->getIndex());
- else
- mangleUnscopedName(ND->getTemplatedDecl());
+ } else {
+ mangleUnscopedName(ND->getTemplatedDecl(), AdditionalAbiTags);
+ }
addSubstitution(ND);
}
-void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
+void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template,
+ const AbiTagList *AdditionalAbiTags) {
// <unscoped-template-name> ::= <unscoped-name>
// ::= <substitution>
if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleUnscopedTemplateName(TD);
+ return mangleUnscopedTemplateName(TD, AdditionalAbiTags);
if (mangleSubstitution(Template))
return;
+ assert(!AdditionalAbiTags && "dependent template name cannot have abi tags"); // TODO(abitags)
+
DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
assert(Dependent && "Not a dependent template name?");
if (const IdentifierInfo *Id = Dependent->getIdentifier())
mangleSourceName(Id);
else
mangleOperatorName(Dependent->getOperator(), UnknownArity);
-
+
addSubstitution(Template);
}
@@ -836,6 +1056,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
else
Out << "sr";
mangleSourceName(qualifier->getAsNamespace()->getIdentifier());
+ writeAbiTags(qualifier->getAsNamespace());
break;
case NestedNameSpecifier::NamespaceAlias:
if (qualifier->getPrefix())
@@ -844,6 +1065,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
else
Out << "sr";
mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier());
+ writeAbiTags(qualifier->getAsNamespaceAlias());
break;
case NestedNameSpecifier::TypeSpec:
@@ -878,6 +1100,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
Out << "sr";
mangleSourceName(qualifier->getAsIdentifier());
+ writeAbiTags(qualifier->getAsNamespaceAlias());
break;
}
@@ -923,7 +1146,8 @@ void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
DeclarationName Name,
- unsigned KnownArity) {
+ unsigned KnownArity,
+ const AbiTagList *AdditionalAbiTags) {
unsigned Arity = KnownArity;
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
@@ -942,6 +1166,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
Out << 'L';
mangleSourceName(II);
+ writeAbiTags(ND, AdditionalAbiTags);
break;
}
@@ -981,6 +1206,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
assert(FD->getIdentifier() && "Data member name isn't an identifier!");
mangleSourceName(FD->getIdentifier());
+ // TODO(abitags): not emitting abi tags: internal name anyway
break;
}
@@ -1001,6 +1227,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
assert(D->getDeclName().getAsIdentifierInfo() &&
"Typedef was not named!");
mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ assert(!AdditionalAbiTags && "Type cannot have additional abi tags");
+ // explicit abi tags are still possible; take from underlying type, not from typedef.
+ writeAbiTags(TD, nullptr);
break;
}
@@ -1010,6 +1239,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
if (Record->isLambda() && Record->getLambdaManglingNumber()) {
+ assert(!AdditionalAbiTags && "Lambda type cannot have additional abi tags");
mangleLambda(Record);
break;
}
@@ -1021,6 +1251,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
if (UnnamedMangle > 1)
Out << llvm::utostr(UnnamedMangle - 2);
Out << '_';
+ writeAbiTags(TD, AdditionalAbiTags);
break;
}
@@ -1053,6 +1284,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// Otherwise, use the complete constructor name. This is relevant if a
// class with a constructor is declared within a constructor.
mangleCXXCtorType(Ctor_Complete);
+ writeAbiTags(ND, AdditionalAbiTags);
break;
case DeclarationName::CXXDestructorName:
@@ -1064,6 +1296,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// Otherwise, use the complete destructor name. This is relevant if a
// class with a destructor is declared within a destructor.
mangleCXXDtorType(Dtor_Complete);
+ writeAbiTags(ND, AdditionalAbiTags);
break;
case DeclarationName::CXXOperatorName:
@@ -1079,6 +1312,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXLiteralOperatorName:
mangleOperatorName(Name, Arity);
+ writeAbiTags(ND, AdditionalAbiTags);
break;
case DeclarationName::CXXUsingDirective:
@@ -1095,7 +1329,9 @@ void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
const DeclContext *DC,
- bool NoFunction) {
+ const AbiTagList *AdditionalAbiTags,
+ bool NoFunction,
+ bool ExcludeUnqualifiedName) {
// <nested-name>
// ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
@@ -1115,30 +1351,35 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleTemplatePrefix(TD, NoFunction);
+ mangleTemplatePrefix(TD, AdditionalAbiTags, NoFunction, ExcludeUnqualifiedName);
mangleTemplateArgs(*TemplateArgs);
}
else {
manglePrefix(DC, NoFunction);
- mangleUnqualifiedName(ND);
+ if (!ExcludeUnqualifiedName)
+ mangleUnqualifiedName(ND, AdditionalAbiTags);
}
Out << 'E';
}
void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Out << 'N';
- mangleTemplatePrefix(TD);
+ mangleTemplatePrefix(TD, AdditionalAbiTags, ExcludeUnqualifiedName);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
Out << 'E';
}
-void CXXNameMangler::mangleLocalName(const Decl *D) {
+void CXXNameMangler::mangleLocalName(const Decl *D,
+ const AbiTagList *AdditionalAbiTags,
+ bool ExcludeUnqualifiedName) {
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// <local-name> := Z <function encoding> E d [ <parameter number> ]
@@ -1183,13 +1424,17 @@ void CXXNameMangler::mangleLocalName(const Decl *D) {
// Mangle the name relative to the closest enclosing function.
// equality ok because RD derived from ND above
if (D == RD) {
- mangleUnqualifiedName(RD);
+ if (!ExcludeUnqualifiedName)
+ mangleUnqualifiedName(RD, AdditionalAbiTags);
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
- mangleUnqualifiedBlock(BD);
+ assert(!AdditionalAbiTags && "Block cannot have additional abi tags");
+ if (!ExcludeUnqualifiedName)
+ mangleUnqualifiedBlock(BD);
} else {
const NamedDecl *ND = cast<NamedDecl>(D);
- mangleNestedName(ND, getEffectiveDeclContext(ND), true /*NoFunction*/);
+ mangleNestedName(ND, getEffectiveDeclContext(ND),
+ AdditionalAbiTags, true /*NoFunction*/, ExcludeUnqualifiedName);
}
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
// Mangle a block in a default parameter; see above explanation for
@@ -1206,30 +1451,35 @@ void CXXNameMangler::mangleLocalName(const Decl *D) {
}
}
- mangleUnqualifiedBlock(BD);
+ assert(!AdditionalAbiTags && "Block cannot have additional abi tags");
+ if (!ExcludeUnqualifiedName)
+ mangleUnqualifiedBlock(BD);
} else {
- mangleUnqualifiedName(cast<NamedDecl>(D));
- }
-
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) {
- unsigned disc;
- if (Context.getNextDiscriminator(ND, disc)) {
- if (disc < 10)
- Out << '_' << disc;
- else
- Out << "__" << disc << '_';
+ if (!ExcludeUnqualifiedName)
+ mangleUnqualifiedName(cast<NamedDecl>(D), AdditionalAbiTags);
+ }
+
+ if (!ExcludeUnqualifiedName) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) {
+ unsigned disc;
+ if (Context.getNextDiscriminator(ND, disc)) {
+ if (disc < 10)
+ Out << '_' << disc;
+ else
+ Out << "__" << disc << '_';
+ }
}
}
}
void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) {
if (GetLocalClassDecl(Block)) {
- mangleLocalName(Block);
+ mangleLocalName(Block, /* AdditionalAbiTags */ nullptr, /* ExcludeUnqualifiedName */ false);
return;
}
const DeclContext *DC = getEffectiveDeclContext(Block);
if (isLocalContainerContext(DC)) {
- mangleLocalName(Block);
+ mangleLocalName(Block, /* AdditionalAbiTags */ nullptr, /* ExcludeUnqualifiedName */ false);
return;
}
manglePrefix(getEffectiveDeclContext(Block));
@@ -1240,10 +1490,11 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
if (Decl *Context = Block->getBlockManglingContextDecl()) {
if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
Context->getDeclContext()->isRecord()) {
- if (const IdentifierInfo *Name
- = cast<NamedDecl>(Context)->getIdentifier()) {
+ const auto *ND = cast<NamedDecl>(Context);
+ if (const IdentifierInfo *Name = ND->getIdentifier()) {
mangleSourceName(Name);
- Out << 'M';
+ writeAbiTags(ND, /* AdditionalAbiTags */ nullptr);
+ Out << 'M';
}
}
}
@@ -1276,7 +1527,7 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
if (const IdentifierInfo *Name
= cast<NamedDecl>(Context)->getIdentifier()) {
mangleSourceName(Name);
- Out << 'M';
+ Out << 'M';
}
}
}
@@ -1358,11 +1609,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleTemplatePrefix(TD);
+ mangleTemplatePrefix(TD, /* AdditionalAbiTags */ nullptr);
mangleTemplateArgs(*TemplateArgs);
} else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
- mangleUnqualifiedName(ND);
+ mangleUnqualifiedName(ND, /* AdditionalAbiTags */ nullptr);
}
addSubstitution(ND);
@@ -1373,27 +1624,30 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
// ::= <template-param>
// ::= <substitution>
if (TemplateDecl *TD = Template.getAsTemplateDecl())
- return mangleTemplatePrefix(TD);
+ return mangleTemplatePrefix(TD, /* AdditionalAbiTags */ nullptr);
if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
manglePrefix(Qualified->getQualifier());
-
+
if (OverloadedTemplateStorage *Overloaded
= Template.getAsOverloadedTemplate()) {
mangleUnqualifiedName(nullptr, (*Overloaded->begin())->getDeclName(),
- UnknownArity);
+ UnknownArity,
+ /* AdditionalAbiTags */ nullptr);
return;
}
-
+
DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
assert(Dependent && "Unknown template name kind?");
if (NestedNameSpecifier *Qualifier = Dependent->getQualifier())
manglePrefix(Qualifier);
- mangleUnscopedTemplateName(Template);
+ mangleUnscopedTemplateName(Template, /* AdditionalAbiTags */ nullptr);
}
void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
- bool NoFunction) {
+ const AbiTagList *AdditionalAbiTags,
+ bool NoFunction,
+ bool ExcludeUnqualifiedName) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
// ::= <substitution>
@@ -1405,10 +1659,12 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
// <template-template-param> ::= <template-param>
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ // TODO(abitags): ???
mangleTemplateParameter(TTP->getIndex());
} else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
- mangleUnqualifiedName(ND->getTemplatedDecl());
+ if (!ExcludeUnqualifiedName)
+ mangleUnqualifiedName(ND->getTemplatedDecl(), AdditionalAbiTags);
}
addSubstitution(ND);
@@ -1452,6 +1708,7 @@ void CXXNameMangler::mangleType(TemplateName TN) {
// <name> ::= <nested-name>
mangleUnresolvedPrefix(Dependent->getQualifier());
mangleSourceName(Dependent->getIdentifier());
+ // writeAbiTags(Dependent);
break;
}
@@ -1543,16 +1800,19 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::Typedef:
mangleSourceName(cast<TypedefType>(Ty)->getDecl()->getIdentifier());
+ writeAbiTags(cast<TypedefType>(Ty)->getDecl());
break;
case Type::UnresolvedUsing:
mangleSourceName(
cast<UnresolvedUsingType>(Ty)->getDecl()->getIdentifier());
+ writeAbiTags(cast<UnresolvedUsingType>(Ty)->getDecl());
break;
case Type::Enum:
case Type::Record:
mangleSourceName(cast<TagType>(Ty)->getDecl()->getIdentifier());
+ writeAbiTags(cast<TagType>(Ty)->getDecl());
break;
case Type::TemplateSpecialization: {
@@ -1571,6 +1831,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
goto unresolvedType;
mangleSourceName(TD->getIdentifier());
+ writeAbiTags(TD);
break;
}
@@ -1602,16 +1863,19 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::InjectedClassName:
mangleSourceName(
cast<InjectedClassNameType>(Ty)->getDecl()->getIdentifier());
+ writeAbiTags(cast<InjectedClassNameType>(Ty)->getDecl());
break;
case Type::DependentName:
mangleSourceName(cast<DependentNameType>(Ty)->getIdentifier());
+ // writeAbiTags(cast<DependentNameType>(Ty));
break;
case Type::DependentTemplateSpecialization: {
const DependentTemplateSpecializationType *DTST =
cast<DependentTemplateSpecializationType>(Ty);
mangleSourceName(DTST->getIdentifier());
+ // writeAbiTags(DTST);
mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
break;
}
@@ -2433,7 +2697,11 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
- mangleName(TD, T->getArgs(), T->getNumArgs());
+ // types only have explicit abi tags, no addition tags
+ mangleTemplateName(TD,
+ /* AdditionalAbiTags */ nullptr,
+ /* ExcludeUnqualifiedName */ false,
+ T->getArgs(), T->getNumArgs());
} else {
if (mangleSubstitution(QualType(T, 0)))
return;
@@ -2480,6 +2748,7 @@ void CXXNameMangler::mangleType(const DependentNameType *T) {
Out << 'N';
manglePrefix(T->getQualifier());
mangleSourceName(T->getIdentifier());
+ // writeAbiTags(T); // TODO(abitags)
Out << 'E';
}
@@ -3876,6 +4145,76 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
Substitutions[Ptr] = SeqID++;
}
+std::set<StringRef> CXXNameMangler::getTagsFromPrefixAndTemplateArguments(const NamedDecl *ND) {
+ llvm::raw_null_ostream NullOutStream;
+ CXXNameMangler TrackPrefixAndTemplateArguments(*this, NullOutStream);
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ TrackPrefixAndTemplateArguments.WorkaroundGCCAbiTagBug = false;
+ TrackPrefixAndTemplateArguments.mangleFunctionEncoding(FD, /* ExcludeUnqualifiedName */ true);
+ } else {
+ TrackPrefixAndTemplateArguments.WorkaroundGCCAbiTagBug = true;
+ TrackPrefixAndTemplateArguments.mangleName(ND, /* ExcludeUnqualifiedName */ true);
+ }
+
+ return std::move(TrackPrefixAndTemplateArguments.AbiTagsRoot.UsedAbiTags);
+}
+
+CXXNameMangler::AbiTagList CXXNameMangler::makeAdditionalTagsForFunction(const FunctionDecl *FD) {
+ // when abi tags are disabled there is no need to make any list
+ if (DisableAbiTags) return AbiTagList();
+
+ std::set<StringRef> ImplicitlyAvailableTags = getTagsFromPrefixAndTemplateArguments(FD);
+ std::set<StringRef> ReturnTypeTags;
+
+ {
+ llvm::raw_null_ostream NullOutStream;
+ CXXNameMangler TrackReturnTypeTags(*this, NullOutStream);
+
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>());
+ TrackReturnTypeTags.FunctionTypeDepth.enterResultType();
+ TrackReturnTypeTags.mangleType(Proto->getReturnType());
+ TrackReturnTypeTags.FunctionTypeDepth.leaveResultType();
+
+ ReturnTypeTags = std::move(TrackReturnTypeTags.AbiTagsRoot.UsedAbiTags);
+ }
+
+ AbiTagList AdditionalAbiTags;
+
+ for (const auto& Tag: ReturnTypeTags) {
+ if (ImplicitlyAvailableTags.count(Tag) == 0)
+ AdditionalAbiTags.push_back(Tag);
+ }
+
+ return AdditionalAbiTags;
+}
+
+CXXNameMangler::AbiTagList CXXNameMangler::makeAdditionalTagsForVariable(const VarDecl *VD) {
+ // when abi tags are disabled there is no need to make any list
+ if (DisableAbiTags) return AbiTagList();
+
+ std::set<StringRef> ImplicitlyAvailableTags = getTagsFromPrefixAndTemplateArguments(VD);
+ std::set<StringRef> VariableTypeTags;
+
+ {
+ llvm::raw_null_ostream NullOutStream;
+ CXXNameMangler TrackVariableType(*this, NullOutStream);
+
+ TrackVariableType.mangleType(VD->getType());
+
+ VariableTypeTags = std::move(TrackVariableType.AbiTagsRoot.UsedAbiTags);
+ }
+
+ AbiTagList AdditionalAbiTags;
+
+ for (const auto& Tag: VariableTypeTags) {
+ if (ImplicitlyAvailableTags.count(Tag) == 0)
+ AdditionalAbiTags.push_back(Tag);
+ }
+
+ return AdditionalAbiTags;
+}
+
//
/// Mangles the name of the declaration D and emits that name to the given
@@ -3977,6 +4316,7 @@ void ItaniumMangleContextImpl::mangleStaticGuardVariable(const VarDecl *D,
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
CXXNameMangler Mangler(*this, Out);
+ Mangler.disableAbiTags(); // GCC BUG: doesn't emit abi tags for guard variables
Mangler.getStream() << "_ZGV";
Mangler.mangleName(D);
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 31ed9f2..ac85f30 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -4167,6 +4167,58 @@ static void handleDeclspecThreadAttr(Sema &S, Decl *D,
Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
}
+static void handleAbiTagAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ SmallVector<std::string, 4> Tags;
+
+ for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) {
+ StringRef Tag;
+
+ if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag))
+ return;
+
+ Tags.push_back(Tag);
+ }
+ // store tags sorted and without duplicates
+ std::sort(Tags.begin(), Tags.end());
+ Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
+
+ if (const auto *NS = dyn_cast<NamespaceDecl>(D)) {
+ if (!NS->isInline()) {
+ S.Diag(Attr.getLoc(), diag::err_attr_abi_tag_only_on_inline_namespace);
+ return;
+ }
+ }
+
+ const auto *CD = D->getCanonicalDecl();
+ if (CD != D) {
+ // redeclarations must not add new abi tags, or abi tags in the first place
+ const auto *OldAbiTagAttr = D->getAttr<AbiTagAttr>();
+ if (nullptr == OldAbiTagAttr) {
+ S.Diag(Attr.getLoc(), diag::err_abi_tag_on_redeclaration);
+ S.Diag(CD->getLocation(), diag::note_previous_definition);
+ return;
+ }
+ for (const auto& NewTag: Tags) {
+ if (std::find(OldAbiTagAttr->tags_begin(),
+ OldAbiTagAttr->tags_end(),
+ NewTag) == OldAbiTagAttr->tags_end()) {
+ S.Diag(Attr.getLoc(), diag::err_new_abi_tag_on_redeclaration) << NewTag;
+ S.Diag(OldAbiTagAttr->getLocation(), diag::note_previous_definition);
+ return;
+ }
+ }
+ return;
+ }
+
+ D->addAttr(::new (S.Context) AbiTagAttr(Attr.getRange(), S.Context,
+ Tags.data(), Tags.size(),
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleARMInterruptAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
// Check the attribute arguments.
@@ -4982,6 +5034,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
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:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment