eugenis updated this revision to Diff 39245.

Repository:
  rL LLVM

http://reviews.llvm.org/D13925

Files:
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/CodeGenCXX/attribute_internal_linkage.cpp
  test/Sema/attr-coldhot.c
  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,44 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+int f() __attribute__((internal_linkage));
+
+class A;
+class __attribute__((internal_linkage)) A {
+public:
+  int x __attribute__((internal_linkage)); // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+  static int y __attribute__((internal_linkage));
+  void f1() __attribute__((internal_linkage));
+  void f2() __attribute__((internal_linkage)) {}
+  static void f3() __attribute__((internal_linkage)) {}
+  void f4(); // expected-note{{previous definition is here}}
+  static int zz; // expected-note{{previous definition is here}}
+  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 only applies to variables, functions and classes}}
+  };
+};
+
+__attribute__((internal_linkage)) void A::f4() {} // expected-error{{internal_linkage attribute does not appear on the first declaration of 'f4'}}
+
+__attribute__((internal_linkage)) int A::zz; // expected-error{{internal_linkage attribute does not appear on the first declaration of 'zz'}}
+
+namespace Z __attribute__((internal_linkage)) { // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+}
+
+__attribute__((internal_linkage("foo"))) int g() {} // expected-error{{'internal_linkage' attribute takes no arguments}}
+
+[[clang::internal_linkage]] int h() {}
+
+int hh(int a [[clang::internal_linkage]]) {}
+
+enum struct __attribute__((internal_linkage)) E { // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+  a = 1,
+  b = 2
+};
+
+int A::y;
+
+void A::f1() {
+}
Index: test/Sema/internal_linkage.c
===================================================================
--- /dev/null
+++ test/Sema/internal_linkage.c
@@ -0,0 +1,21 @@
+// 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}} \
+// expected-note{{previous definition is here}}
+int var4 __attribute__((internal_linkage)); // expected-note{{conflicting attribute is here}} \
+// expected-error{{internal_linkage attribute does not appear on the first declaration of 'var4'}}
+
+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 { // expected-warning{{'internal_linkage' attribute only applies to variables and functions}}
+};
+
+__attribute__((internal_linkage("foo"))) int g() {} // expected-error{{'internal_linkage' attribute takes no arguments}}
Index: test/Sema/attr-coldhot.c
===================================================================
--- test/Sema/attr-coldhot.c
+++ test/Sema/attr-coldhot.c
@@ -6,5 +6,7 @@
 int var1 __attribute__((__cold__)); // expected-warning{{'__cold__' attribute only applies to functions}}
 int var2 __attribute__((__hot__)); // expected-warning{{'__hot__' attribute only applies to functions}}
 
-int qux() __attribute__((__hot__)) __attribute__((__cold__)); // expected-error{{'__hot__' and 'cold' attributes are not compatible}}
-int baz() __attribute__((__cold__)) __attribute__((__hot__)); // expected-error{{'__cold__' and 'hot' attributes are not compatible}}
+int qux() __attribute__((__hot__)) __attribute__((__cold__)); // expected-error{{'__hot__' and 'cold' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
+int baz() __attribute__((__cold__)) __attribute__((__hot__)); // expected-error{{'__cold__' and 'hot' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
Index: test/CodeGenCXX/attribute_internal_linkage.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attribute_internal_linkage.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+__attribute__((internal_linkage)) void f() {}
+// CHECK-DAG: define internal void @_ZL1fv
+
+class A {
+public:
+  static int y __attribute__((internal_linkage));
+  static int y2 [[clang::internal_linkage]];
+// CHECK-DAG: @_ZN1A1yE = internal global
+// CHECK-DAG: @_ZN1A2y2E = internal global
+  void f1() __attribute__((internal_linkage));
+// CHECK-DAG: define internal void @_ZN1A2f1Ev
+  void f2() __attribute__((internal_linkage)) {}
+// CHECK-DAG: define internal void @_ZN1A2f2Ev
+  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;
+int A::y2;
+
+void A::f1() {
+}
+
+// Forward declaration w/o an attribute.
+class B;
+
+// 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;
+
+// Forward declaration with the attribute.
+class __attribute__((internal_linkage)) C;
+class C {
+public:
+  static int x;
+  // CHECK-DAG: @_ZNL1C1xE = internal global
+};
+
+int C::x;
+
+__attribute__((internal_linkage)) void g();
+void g() {}
+// CHECK-DAG: define internal void @_ZL1gv()
+
+void use() {
+  A a;
+  a.f1();
+  a.f2();
+  A::f4();
+  f();
+  int &Y = A::y;
+  int &Y2 = A::y2;
+  B b;
+  b.f();
+  int &XX2 = B::x;
+  g();
+  int &XX3 = C::x;
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -244,11 +244,12 @@
 /// \brief Diagnose mutually exclusive attributes when present on a given
 /// declaration. Returns true if diagnosed.
 template <typename AttrTy>
-static bool checkAttrMutualExclusion(Sema &S, Decl *D,
-                                     const AttributeList &Attr) {
+static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range,
+                                     IdentifierInfo *Ident) {
   if (AttrTy *A = D->getAttr<AttrTy>()) {
-    S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
-      << Attr.getName() << A;
+    S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident
+                                                                      << A;
+    S.Diag(A->getLocation(), diag::note_conflicting_attribute);
     return true;
   }
   return false;
@@ -1523,15 +1524,15 @@
 }
 
 static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (checkAttrMutualExclusion<HotAttr>(S, D, Attr))
+  if (checkAttrMutualExclusion<HotAttr>(S, D, Attr.getRange(), Attr.getName()))
     return;
 
   D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context,
                                         Attr.getAttributeSpellingListIndex()));
 }
 
 static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
-  if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr))
+  if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr.getRange(), Attr.getName()))
     return;
 
   D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context,
@@ -1573,12 +1574,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.getName(),
+                                         Attr.getAttributeSpellingListIndex()))
+    D->addAttr(CA);
 }
 
 static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
@@ -3383,6 +3385,26 @@
                                           AttrSpellingListIndex);
 }
 
+CommonAttr *Sema::mergeCommonAttr(Decl *D, SourceRange Range,
+                                  IdentifierInfo *Ident,
+                                  unsigned AttrSpellingListIndex) {
+  if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, Range, Ident))
+    return nullptr;
+
+  return ::new (Context) CommonAttr(Range, Context, AttrSpellingListIndex);
+}
+
+InternalLinkageAttr *
+Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range,
+                               IdentifierInfo *Ident,
+                               unsigned AttrSpellingListIndex) {
+  if (checkAttrMutualExclusion<CommonAttr>(*this, D, Range, Ident))
+    return nullptr;
+
+  return ::new (Context)
+      InternalLinkageAttr(Range, Context, AttrSpellingListIndex);
+}
+
 MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
                                     unsigned AttrSpellingListIndex) {
   if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
@@ -4002,7 +4024,8 @@
 
 static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
                                         const AttributeList &Attr) {
-  if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr))
+  if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(),
+                                                      Attr.getName()))
     return;
 
   D->addAttr(::new (S.Context)
@@ -4012,7 +4035,8 @@
 
 static void handleCFUnknownTransferAttr(Sema &S, Decl *D,
                                         const AttributeList &Attr) {
-  if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr))
+  if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr.getRange(),
+                                                      Attr.getName()))
     return;
 
   D->addAttr(::new (S.Context)
@@ -4634,6 +4658,14 @@
                                 Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleInternalLinkageAttr(Sema &S, Decl *D,
+                                      const AttributeList &Attr) {
+  if (InternalLinkageAttr *Internal =
+          S.mergeInternalLinkageAttr(D, Attr.getRange(), Attr.getName(),
+                                     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.
@@ -5075,6 +5107,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,15 @@
     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(),
+        &S.Context.Idents.get(InternalLinkageA->getSpelling()),
+        AttrSpellingListIndex);
+  else if (const auto *CommonA = dyn_cast<CommonAttr>(Attr))
+    NewAttr = S.mergeCommonAttr(D, CommonA->getRange(),
+                                &S.Context.Idents.get(CommonA->getSpelling()),
+                                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.
@@ -2664,6 +2673,13 @@
     }
   }
 
+  if (New->hasAttr<InternalLinkageAttr>() &&
+      !Old->hasAttr<InternalLinkageAttr>()) {
+    Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
+        << New->getDeclName();
+    Diag(Old->getLocation(), diag::note_previous_definition);
+    New->dropAttr<InternalLinkageAttr>();
+  }
 
   // If a function is first declared with a calling convention, but is later
   // declared or defined without one, all following decls assume the calling
@@ -3377,6 +3393,14 @@
     New->dropAttr<WeakImportAttr>();
   }
 
+  if (New->hasAttr<InternalLinkageAttr>() &&
+      !Old->hasAttr<InternalLinkageAttr>()) {
+    Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
+        << New->getDeclName();
+    Diag(Old->getLocation(), diag::note_previous_definition);
+    New->dropAttr<InternalLinkageAttr>();
+  }
+
   // Merge the types.
   VarDecl *MostRecent = Old->getMostRecentDecl();
   if (MostRecent != Old) {
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1224,6 +1224,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()) {
@@ -1314,6 +1318,10 @@
 public:
   static LinkageInfo getLVForDecl(const NamedDecl *D,
                                   LVComputationKind computation) {
+    // Internal_linkage attribute overrides other considerations.
+    if (D->hasAttr<InternalLinkageAttr>())
+      return LinkageInfo::internal();
+
     if (computation == LVForLinkageOnly && D->hasCachedLinkage())
       return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -2106,6 +2106,11 @@
                                 unsigned AttrSpellingListIndex);
   OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
                                           unsigned AttrSpellingListIndex);
+  InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, SourceRange Range,
+                                                IdentifierInfo *Ident,
+                                                unsigned AttrSpellingListIndex);
+  CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident,
+                              unsigned AttrSpellingListIndex);
 
   void mergeDeclAttributes(NamedDecl *New, Decl *Old,
                            AvailabilityMergeKind AMK = AMK_Redeclaration);
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4080,6 +4080,9 @@
   InGroup<DiagGroup<"undefined-inline">>;
 def note_used_here : Note<"used here">;
 
+def err_internal_linkage_redeclaration : Error<
+  "internal_linkage attribute does not appear on the first declaration of %0">;
+
 def ext_internal_in_extern_inline : ExtWarn<
   "static %select{function|variable}0 %1 is used in an inline function with "
   "external linkage">, InGroup<StaticInInline>;
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -1620,3 +1620,13 @@
 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.
+This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition,
+this attribute affects all methods and static data members of that class.
+This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables.
+  }];
+}
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -2125,3 +2125,9 @@
   let SemaHandler = 0;
   let Documentation = [Undocumented];
 }
+
+def InternalLinkage : InheritableAttr {
+  let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">];
+  let Subjects = SubjectList<[Var, Function, CXXRecord]>;
+  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