Bug 23529: Add support for gcc's attribute abi_tag (needed for compatibility with gcc 5's libstdc++)

2015-09-12 Thread Stefan Bühler via cfe-commits
Hi all,

I've been working on #23529.

The abi tag mangling implemented by gcc is horrible, but I think my
patch covers most of the incompatibilities with gcc5.

There might be some bugs with substitutions, although I have to come up
with a test case for that to see what gcc does...

Test cases comparing gcc and patched clang++:
http://files.stbuehler.de/test-itanium-mangle.html
(generated with http://files.stbuehler.de/test-itanium-mangle.sh, also
attached)

regards,
Stefan
Author: Stefan Bühler 

add gcc abi_tag support

- parse abi_tag attribute
- emit abi tags in name Itanium Mangling
- try to emit the same tags as gcc5

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;
 def err_attribute_wrong_decl_type : Error;
 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..bb16ebe 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -214,6 +214,8 @@ public:
 class CXXNameMangler {
   ItaniumMangleContextImpl &Context;
   raw_ostream &Out;
+  bool NullOut = false;
+  bool DisableDerivedAbiTags = false;
 
   /// The "structor" is the top-level declaration being mangled, if
   /// that's not a template specialization; otherwise it's the pattern
@@ -263,6 +265,167 @@ 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  (i.e.
+  // parameters and sometimes the return type).
+  //
+  // For functions this is basically the list of all tags from the signature
+  // without the unqualifi

Re: Bug 23529: Add support for gcc's attribute abi_tag (needed for compatibility with gcc 5's libstdc++)

2015-09-27 Thread Stefan Bühler via cfe-commits
Hi,

it seems moderation didn't approve the phabricator mails for D12834.
(I have no intention to be subscribed to the list just to get
phabricator mails through. For now I am subscribed but disabled
mail delivery -.-)

So the patch is available at http://reviews.llvm.org/D12834

I also added a test case which shows that substitution is not
working correctly right now.

regards,
Stefan

PS: I think contributing to llvm is way to complex. First I attatch
patches in the bug tracker, and it takes ages to get a reaction - and
them I'm simply told to send to the ML. Then you want me to use
phabricator, and then I get no feedback again - because moderation
blocked emails from an internal system, and it seems nobody is looking
at phabricator directly.
This is not something I look forward to go through again; my
motiviation to contribute further is rather low.


On Sat, 12 Sep 2015 12:36:19 -0700
David Majnemer  wrote:

> Would you mind sticking abi-tag.patch in phabricator:
> http://llvm.org/docs/Phabricator.html ?
> Your patch is big enough that it would make it a little easier for me
> to review.
> 
> On Sat, Sep 12, 2015 at 7:12 AM, Stefan Bühler via cfe-commits <
> cfe-commits@lists.llvm.org> wrote:
> 
> > Hi all,
> >
> > I've been working on #23529.
> >
> > The abi tag mangling implemented by gcc is horrible, but I think my
> > patch covers most of the incompatibilities with gcc5.
> >
> > There might be some bugs with substitutions, although I have to
> > come up with a test case for that to see what gcc does...
> >
> > Test cases comparing gcc and patched clang++:
> > http://files.stbuehler.de/test-itanium-mangle.html
> > (generated with http://files.stbuehler.de/test-itanium-mangle.sh,
> > also attached)
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D12834: add gcc abi_tag support

2015-09-27 Thread Stefan Bühler via cfe-commits
stbuehler added a comment.

Just for the record: substitution doesn't work yet (it should add available 
tags from the substitution, but doesn't).

This example shows the difference: my patch mangles `T::F()` as 
`N::Name(N::__test::Result)::T::F[abi:test](N::__test::Result)`, but actually 
shouldn't emit the abi tag.

  namespace N {
inline namespace __test
__attribute__((abi_tag("test"))) {
  struct Result {
const char *str;
  };
}
  
inline Result Name(Result p1) {
  struct T {
Result F(Result p2) {
  struct S {
Result F(Result p3) {
  static Result s3 = p3;
  return s3;
}
  };
  static Result s2 = S().F(p2);
  return s2;
}
  };
  static Result s1 = T().F(p1);
  return s1;
}
  
void F() {
  // instantiate Name()
  Name(Result());
}
  }


Repository:
  rL LLVM

http://reviews.llvm.org/D12834



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D12834: add gcc abi_tag support

2016-01-15 Thread Stefan Bühler via cfe-commits
stbuehler updated this revision to Diff 44972.
stbuehler marked an inline comment as done.
stbuehler added a comment.

- disable dervied abi tags in some recursions to fix infinite recursions
- don't emit abi tags for NestedNameSpecifier::Identifier


Repository:
  rL LLVM

http://reviews.llvm.org/D12834

Files:
  docs/ItaniumMangleAbiTags.rst
  include/clang/Basic/Attr.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/AttributeList.h
  lib/AST/ItaniumMangle.cpp
  lib/Sema/SemaDeclAttr.cpp

Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4446,6 +4446,58 @@
   Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleAbiTagAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+  if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+return;
+
+  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);
+  }
+  // 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(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();
+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.
@@ -5360,6 +5412,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: lib/AST/ItaniumMangle.cpp
===
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -212,6 +212,8 @@
 class CXXNameMangler {
   ItaniumMangleContextImpl &Context;
   raw_ostream &Out;
+  bool NullOut = false;
+  bool DisableDerivedAbiTags = false;
 
   /// The "structor" is the top-level declaration being mangled, if
   /// that's not a template specialization; otherwise it's the pattern
@@ -261,6 +263,167 @@
 
   } 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  (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 namesp

Re: [PATCH] D12834: add gcc abi_tag support

2016-01-15 Thread Stefan Bühler via cfe-commits
stbuehler updated this revision to Diff 44973.
stbuehler added a comment.

integrate patch by Stephan Bergmann :

- Fix handling of abi_tag attribute on namespaces to match GCC behavior:
  - Forbid the attribute on unnamed namespaces.  (GCC merely produces a warning 
instead of an error for unnamed or non-inline namespaces, though.)
  - When no tags are given for a (named, inline) namespace, use the namespace's 
name as tag.


Repository:
  rL LLVM

http://reviews.llvm.org/D12834

Files:
  docs/ItaniumMangleAbiTags.rst
  include/clang/Basic/Attr.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/AttributeList.h
  lib/AST/ItaniumMangle.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/SemaCXX/attr-abi-tag-syntax.cpp
  test/SemaCXX/attr-abi-tag.cpp

Index: test/SemaCXX/attr-abi-tag.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-abi-tag.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple x86_64-unknown-linux -emit-llvm < %s | FileCheck %s
+
+// CHECK: @_Z5Func1B6Names1v()
+inline namespace Names1 __attribute__((__abi_tag__)) {
+class C1 {};
+}
+C1 Func1() { return C1(); }
+
+// CHECK: @_Z5Func2B4Tag1B4Tag2v()
+inline namespace Names2 __attribute__((__abi_tag__("Tag1", "Tag2"))) {
+class C2 {};
+}
+C2 Func2() { return C2(); }
Index: test/SemaCXX/attr-abi-tag-syntax.cpp
===
--- /dev/null
+++ test/SemaCXX/attr-abi-tag-syntax.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+namespace N1 {
+
+namespace __attribute__((__abi_tag__)) {} // \
+  // expected-error {{abi_tag attribute only allowed on inline namespaces}}
+
+namespace N __attribute__((__abi_tag__)) {} // \
+  // expected-error {{abi_tag attribute only allowed on inline namespaces}}
+
+}
+
+namespace N2 {
+
+inline namespace __attribute__((__abi_tag__)) {} // \
+  // expected-error {{abi_tag attribute only allowed on named namespaces}}
+
+inline namespace N __attribute__((__abi_tag__)) {}
+
+}
Index: lib/Sema/SemaDeclAttr.cpp
===
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4446,6 +4446,66 @@
   Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleAbiTagAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+  const auto *NS = dyn_cast(D);
+
+  if (!checkAttributeAtLeastNumArgs(S, Attr, NS ? 0 : 1))
+return;
+
+  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 (NS && !NS->isInline()) {
+S.Diag(Attr.getLoc(), diag::err_attr_abi_tag_only_on_inline_namespace);
+return;
+  }
+  if (NS && NS->isAnonymousNamespace()) {
+S.Diag(Attr.getLoc(), diag::err_attr_abi_tag_only_on_named_namespace);
+return;
+  }
+  if (NS && Attr.getNumArgs() == 0) {
+  Tags.push_back(NS->getName());
+  }
+
+  // store tags sorted and without duplicates
+  std::sort(Tags.begin(), Tags.end());
+  Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
+
+  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();
+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.
@@ -5360,6 +5420,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: lib/AST/ItaniumMangle.cpp
===
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -212,6 +212,8 @@
 class CXXNameMangler {
   ItaniumMangleContextImpl &Context;
   raw_ostream &Out;
+  bool NullOut = false;
+