eugenis updated this revision to Diff 38679.

Repository:
  rL LLVM

http://reviews.llvm.org/D13925

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Sema/Sema.h
  lib/AST/Decl.cpp
  lib/Sema/Sema.cpp
  lib/Sema/SemaDecl.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,17 @@
+// 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}}
+
+int var4 __attribute__((common)); // expected-error{{'common' and 'internal_linkage' attributes are not compatible}}
+int var4 __attribute__((internal_linkage)); // expected-note{{conflicting attribute is here}}
+
+int var5 __attribute__((internal_linkage)); // expected-error{{'internal_linkage' and 'common' attributes are not compatible}}
+int var5 __attribute__((common)); // 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,12 +1573,13 @@
 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;
   }
 
-  D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context,
-                                        Attr.getAttributeSpellingListIndex()));
+  if (CommonAttr *CA = S.mergeCommonAttr(D, Attr.getRange(),
+                                         Attr.getAttributeSpellingListIndex()))
+    D->addAttr(CA);
 }
 
 static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
@@ -3299,6 +3300,34 @@
                                           AttrSpellingListIndex);
 }
 
+CommonAttr *Sema::mergeCommonAttr(Decl *D, SourceRange Range,
+                                  unsigned AttrSpellingListIndex) {
+
+  if (InternalLinkageAttr *Internal = D->getAttr<InternalLinkageAttr>()) {
+    Diag(Range.getBegin(), diag::err_attributes_are_not_compatible)
+        << "'common'" << Internal;
+    Diag(Internal->getLocation(), diag::note_conflicting_attribute);
+    return nullptr;
+  }
+
+  return ::new (Context) CommonAttr(Range, Context, AttrSpellingListIndex);
+}
+
+InternalLinkageAttr *
+Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range,
+                               unsigned AttrSpellingListIndex) {
+
+  if (CommonAttr *Common = D->getAttr<CommonAttr>()) {
+    Diag(Range.getBegin(), diag::err_attributes_are_not_compatible)
+        << "'internal_linkage'" << Common;
+    Diag(Common->getLocation(), diag::note_conflicting_attribute);
+    return nullptr;
+  }
+
+  return ::new (Context)
+      InternalLinkageAttr(Range, Context, AttrSpellingListIndex);
+}
+
 MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
                                     unsigned AttrSpellingListIndex) {
   if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
@@ -4550,6 +4579,20 @@
                                 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 (InternalLinkageAttr *Internal = S.mergeInternalLinkageAttr(
+          D, Attr.getRange(), Attr.getAttributeSpellingListIndex()))
+    D->addAttr(Internal);
+}
+
 /// 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 +5034,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/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -2216,6 +2216,11 @@
     NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex);
   else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
     NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex);
+  else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
+    NewAttr = S.mergeInternalLinkageAttr(D, InternalLinkageA->getRange(),
+                                         AttrSpellingListIndex);
+  else if (const auto *CommonA = dyn_cast<CommonAttr>(Attr))
+    NewAttr = S.mergeCommonAttr(D, CommonA->getRange(), AttrSpellingListIndex);
   else if (isa<AlignedAttr>(Attr))
     // AlignedAttrs are handled separately, because we need to handle all
     // such attributes on a declaration at the same time.
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/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2116,6 +2116,10 @@
                                 unsigned AttrSpellingListIndex);
   OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
                                           unsigned AttrSpellingListIndex);
+  InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, SourceRange Range,
+                                                unsigned AttrSpellingListIndex);
+  CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range,
+                              unsigned AttrSpellingListIndex);
 
   void mergeDeclAttributes(NamedDecl *New, Decl *Old,
                            AvailabilityMergeKind AMK = AMK_Redeclaration);
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