eugenis updated this revision to Diff 38071.
eugenis marked 2 inline comments as done.
eugenis added a comment.

This new version supports __attribute__((internal_linkage)) on classes and even 
namespaces!


Repository:
  rL LLVM

http://reviews.llvm.org/D13925

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  lib/AST/Decl.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/CodeGenCXX/attribute_internal_linkage.cpp
  test/Sema/internal_linkage.c
  test/SemaCXX/internal_linkage.cpp

Index: test/SemaCXX/internal_linkage.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/internal_linkage.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int f() __attribute__((internal_linkage));
+class __attribute__((internal_linkage)) A {
+public:
+  int x __attribute__((internal_linkage)); // expected-warning{{'internal_linkage' attribute ignored}}
+  static int y __attribute__((internal_linkage));
+  void f1() __attribute__((internal_linkage));
+  void f2() __attribute__((internal_linkage)) {}
+  static void f3() __attribute__((internal_linkage)) {}
+  A() __attribute__((internal_linkage)) {}
+  ~A() __attribute__((internal_linkage)) {}
+  A& operator=(const A&) __attribute__((internal_linkage)) { return *this; }
+  struct {
+    int z  __attribute__((internal_linkage)); // expected-warning{{'internal_linkage' attribute ignored}}
+  };
+};
+
+namespace Z __attribute__((internal_linkage)) {
+}
+
+int A::y;
+
+void A::f1() {
+}
Index: test/Sema/internal_linkage.c
===================================================================
--- /dev/null
+++ test/Sema/internal_linkage.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+int var __attribute__((internal_linkage));
+int var2 __attribute__((internal_linkage,common)); // expected-error{{'internal_linkage' and 'common' attributes are not compatible}} \
+                                                   // expected-note{{conflicting attribute is here}}
+int var3 __attribute__((common,internal_linkage)); // expected-error{{'common' and 'internal_linkage' attributes are not compatible}} \
+                                                   // expected-note{{conflicting attribute is here}}
+
+ __attribute__((internal_linkage)) int f() {}
+struct __attribute__((internal_linkage)) S {
+};
Index: test/CodeGenCXX/attribute_internal_linkage.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attribute_internal_linkage.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+__attribute__((internal_linkage)) static void f() {}
+// CHECK-DAG: define internal void @_ZL1fv
+
+class A {
+public:
+  static int y __attribute__((internal_linkage));
+// CHECK-DAG: @_ZN1A1yE = internal global
+  void f1() __attribute__((internal_linkage));
+// CHECK-DAG: define internal void @_ZN1A2f1Ev
+  void f2() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1A2f2Ev
+  void f3();
+// CHECK-DAG: define internal void @_ZN1A2f3Ev
+  static void f4() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1A2f4Ev
+  A() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1AC1Ev
+// CHECK-DAG: define internal void @_ZN1AC2Ev
+  ~A() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1AD1Ev
+// CHECK-DAG: define internal void @_ZN1AD2Ev
+};
+
+int A::y;
+
+void A::f1() {
+}
+
+__attribute__((internal_linkage)) void A::f3() {
+}
+
+// Internal_linkage on a namespace affects everything within.
+namespace ZZZ __attribute__((internal_linkage)) {
+int x;
+// CHECK-DAG: @_ZNL3ZZZL1xE = internal global
+void f() {}
+// CHECK-DAG: define internal void @_ZNL3ZZZL1fEv
+class A {
+public:
+  A() {}
+// CHECK-DAG: define internal void @_ZNL3ZZZL1AC1Ev
+// CHECK-DAG: define internal void @_ZNL3ZZZL1AC2Ev
+  ~A() {}
+// CHECK-DAG: define internal void @_ZNL3ZZZL1AD1Ev
+// CHECK-DAG: define internal void @_ZNL3ZZZL1AD2Ev
+  void g() {};
+// CHECK-DAG: define internal void @_ZNL3ZZZL1A1gEv
+};
+}
+
+// Internal_linkage on a class affects all its members.
+class __attribute__((internal_linkage)) B {
+public:
+  B() {}
+  // CHECK-DAG: define internal void @_ZNL1BC1Ev
+  // CHECK-DAG: define internal void @_ZNL1BC2Ev
+  ~B() {}
+  // CHECK-DAG: define internal void @_ZNL1BD1Ev
+  // CHECK-DAG: define internal void @_ZNL1BD2Ev
+  void f() {};
+  // CHECK-DAG: define internal void @_ZNL1B1fEv
+  static int x;
+  // CHECK-DAG: @_ZNL1B1xE = internal global
+};
+
+int B::x;
+
+void use() {
+  A a;
+  a.f1();
+  a.f2();
+  a.f3();
+  A::f4();
+  f();
+  int &Y = A::y;
+  ZZZ::A za;
+  za.g();
+  ZZZ::f();
+  int &X = ZZZ::x;
+  B b;
+  b.f();
+  int &X2 = B::x;
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -1573,7 +1573,14 @@
 static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   if (S.LangOpts.CPlusPlus) {
     S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang)
-      << Attr.getName() << AttributeLangSupport::Cpp;
+        << Attr.getName() << AttributeLangSupport::Cpp;
+    return;
+  }
+
+  if (InternalLinkageAttr *Internal = D->getAttr<InternalLinkageAttr>()) {
+    S.Diag(Attr.getRange().getBegin(), diag::err_attributes_are_not_compatible)
+        << Attr.getName() << Internal;
+    S.Diag(Internal->getLocation(), diag::note_conflicting_attribute);
     return;
   }
 
@@ -4550,6 +4557,27 @@
                                 Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleInternalLinkageAttr(Sema &S, Decl *D,
+                                      const AttributeList &Attr) {
+  if (!(isa<FunctionDecl>(D) || isa<VarDecl>(D) || isa<TagDecl>(D) ||
+        isa<NamespaceDecl>(D))) {
+    S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored)
+      << Attr.getName();
+    return;
+  }
+
+  if (CommonAttr *Common = D->getAttr<CommonAttr>()) {
+    S.Diag(Attr.getRange().getBegin(), diag::err_attributes_are_not_compatible)
+        << Attr.getName() << Common;
+    S.Diag(Common->getLocation(), diag::note_conflicting_attribute);
+    return;
+  }
+
+  if (!D->hasAttr<InternalLinkageAttr>())
+    D->addAttr(::new (S.Context) InternalLinkageAttr(
+        Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
 /// Handles semantic checking for features that are common to all attributes,
 /// such as checking whether a parameter was properly specified, or the correct
 /// number of arguments were passed, etc.
@@ -4991,6 +5019,9 @@
   case AttributeList::AT_OpenCLImageAccess:
     handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr);
     break;
+  case AttributeList::AT_InternalLinkage:
+    handleInternalLinkageAttr(S, D, Attr);
+    break;
 
   // Microsoft attributes:
   case AttributeList::AT_MSNoVTable:
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -536,7 +536,7 @@
       continue;
     }
 
-    if (!ND->isExternallyVisible()) {
+    if (!ND->isExternallyVisible() || ND->hasAttr<InternalLinkageAttr>()) {
       S.Diag(ND->getLocation(), diag::warn_undefined_internal)
         << isa<VarDecl>(ND) << ND;
     } else {
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -633,6 +633,13 @@
   }
   assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
 
+  for (const DeclContext *DC = D->getDeclContext();
+       !isa<TranslationUnitDecl>(DC); DC = DC->getParent()) {
+    const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+    if (ND && ND->getAttr<InternalLinkageAttr>())
+      return LinkageInfo::internal();
+  }
+
   if (D->isInAnonymousNamespace()) {
     const VarDecl *Var = dyn_cast<VarDecl>(D);
     const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
@@ -1224,6 +1231,10 @@
 
 static LinkageInfo computeLVForDecl(const NamedDecl *D,
                                     LVComputationKind computation) {
+  // Internal_linkage attribute overrides other considerations.
+  if (D->hasAttr<InternalLinkageAttr>())
+    return LinkageInfo::internal();
+
   // Objective-C: treat all Objective-C declarations as having external
   // linkage.
   switch (D->getKind()) {
@@ -1344,7 +1355,11 @@
         break;
       }
     }
-    assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage());
+    // Linkages may also differ if one of the declarations has
+    // InternalLinkageAttr.
+    assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage() ||
+           (Old->hasAttr<InternalLinkageAttr>() !=
+            D->hasAttr<InternalLinkageAttr>()));
 #endif
 
     return LV;
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -1612,3 +1612,10 @@
 arguments, with arbitrary offsets.
   }];
 }
+
+def InternalLinkageDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The ``internal_linkage`` attribute changes the linkage type of the declaration to internal.
+  }];
+}
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -2108,3 +2108,8 @@
   let SemaHandler = 0;
   let Documentation = [Undocumented];
 }
+
+def InternalLinkage : InheritableAttr {
+  let Spellings = [GCC<"internal_linkage">];
+  let Documentation = [InternalLinkageDocs];
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to