Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2108,3 +2108,9 @@ let SemaHandler = 0; let Documentation = [Undocumented]; } + +def InternalLinkage : InheritableAttr { + let Spellings = [GCC<"internal_linkage">]; + let Subjects = SubjectList<[Function,Var]>; + let Documentation = [InternalLinkageDocs]; +} 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: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8304,6 +8304,8 @@ } else if (D->hasAttr() || D->hasAttr()) { if (L == GVA_DiscardableODR) return GVA_StrongODR; + } else if (D->hasAttr()) { + return GVA_Internal; } return L; } 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()) { S.Diag(ND->getLocation(), diag::warn_undefined_internal) << isa(ND) << ND; } else { 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()) { + S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored) + << Attr.getName(); + S.Diag(Internal->getLocation(), diag::note_conflicting_attribute); return; } @@ -4550,6 +4557,20 @@ Attr.getAttributeSpellingListIndex())); } +static void handleInternalLinkageAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (CommonAttr *Common = D->getAttr()) { + S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored) + << Attr.getName(); + S.Diag(Common->getLocation(), diag::note_conflicting_attribute); + return; + } + + if (!D->hasAttr()) + 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 +5012,9 @@ case AttributeList::AT_OpenCLImageAccess: handleSimpleAttribute(S, D, Attr); break; + case AttributeList::AT_InternalLinkage: + handleInternalLinkageAttr(S, D, Attr); + break; // Microsoft attributes: case AttributeList::AT_MSNoVTable: Index: test/CodeGenCXX/internal_linkage.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/internal_linkage.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +__attribute__((internal_linkage)) static void f() {} + +class A { +public: + static int y __attribute__((internal_linkage)); + void f1() __attribute__((internal_linkage)); + void f2() __attribute__((internal_linkage)) {} + void f3(); + static void f4() __attribute__((internal_linkage)) {} + A() __attribute__((internal_linkage)) {} + ~A() __attribute__((internal_linkage)) {} +}; + +int A::y; + +void A::f1() { +} + +void A::f3() __attribute__((internal_linkage)) { +} + +void use() { + A a; + a.f1(); + a.f2(); + a.f3(); + A::f4(); + f(); + int &Y = A::y; +} + +// CHECK-DAG: @_ZN1A1yE = internal global +// CHECK-DAG: define internal void @_ZL1fv +// CHECK-DAG: define internal void @_ZN1AC1Ev +// CHECK-DAG: define internal void @_ZN1AC2Ev +// CHECK-DAG: define internal void @_ZN1AD1Ev +// CHECK-DAG: define internal void @_ZN1AD2Ev +// CHECK-DAG: define internal void @_ZN1A2f1Ev +// CHECK-DAG: define internal void @_ZN1A2f2Ev +// CHECK-DAG: define internal void @_ZN1A2f3Ev +// CHECK-DAG: define internal void @_ZN1A2f4Ev Index: test/Sema/internal_linkage.c =================================================================== --- /dev/null +++ test/Sema/internal_linkage.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int var __attribute__((internal_linkage)); +int var2 __attribute__((internal_linkage,common)); // expected-warning{{'internal_linkage' attribute ignored}} \ + // expected-note{{conflicting attribute is here}} +int f() __attribute__((internal_linkage)); +struct __attribute__((internal_linkage)) S { // expected-warning{{'internal_linkage' attribute only applies to variables and functions}} +}; Index: test/SemaCXX/internal_linkage.cpp =================================================================== --- /dev/null +++ test/SemaCXX/internal_linkage.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +int f() __attribute__((internal_linkage)); +class __attribute__((internal_linkage)) A { // expected-warning{{'internal_linkage' attribute only applies to variables and functions}} +public: + int x __attribute__((internal_linkage)); // expected-warning{{'internal_linkage' attribute only applies to variables and functions}} + 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)) {} +}; + +int A::y; + +void A::f1() { +}