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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits