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];
+}
// not_tail_called on a virtual function is an error.
[[clang::not_tail_called]] int foo2() override;
};
+ }];
+}
+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.
}];
}
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 warn_internal_linkage_local_storage : Warning<
+ "'internal_linkage' attribute on a non-static local variable is ignored">,
+ InGroup<IgnoredAttributes>;
+
def ext_internal_in_extern_inline : ExtWarn<
"static %select{function|variable}0 %1 is used in an inline function with "
"external linkage">, InGroup<StaticInInline>;
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);
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()) {
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);
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.
}
}
+ 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
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) {
/// \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;
}
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,
}
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,
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) {
static void handleNotTailCalledAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
return;
D->addAttr(::new (S.Context) NotTailCalledAttr(
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 (auto VD = dyn_cast<VarDecl>(D)) {
+ // Attribute applies to Var but not any subclass of it (like ParmVar,
+ // ImplicitParm or VarTemplateSpecialization).
+ if (VD->getKind() != Decl::Var) {
+ Diag(Range.getBegin(), diag::warn_attribute_wrong_decl_type)
+ << Ident << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
+ : ExpectedVariableOrFunction);
+ return nullptr;
+ }
+ // Attribute does not apply to non-static local variables.
+ if (VD->hasLocalStorage()) {
+ Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage);
+ return nullptr;
+ }
+ }
+
+ 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>()) {
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
- if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr))
+ if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(),
+ Attr.getName()))
return;
if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
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)
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)
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.
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:
--- /dev/null
+// 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;
+}
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}}
// RUN: %clang_cc1 -fsyntax-only -verify %s
-int callee0() __attribute__((not_tail_called,always_inline)); // expected-error{{'not_tail_called' and 'always_inline' attributes are not compatible}}
-int callee1() __attribute__((always_inline,not_tail_called)); // expected-error{{'always_inline' and 'not_tail_called' attributes are not compatible}}
+int callee0() __attribute__((not_tail_called,always_inline)); // expected-error{{'not_tail_called' and 'always_inline' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
+int callee1() __attribute__((always_inline,not_tail_called)); // expected-error{{'always_inline' and 'not_tail_called' attributes are not compatible}} \
+// expected-note{{conflicting attribute is here}}
int foo(int a) {
return a ? callee0() : callee1();
--- /dev/null
+// 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}}
--- /dev/null
+// 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() {}
+
+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() {
+}
+
+void g(int a [[clang::internal_linkage]]) { // expected-warning{{'internal_linkage' attribute only applies to variables, functions and classes}}
+ int x [[clang::internal_linkage]]; // expected-warning{{'internal_linkage' attribute on a non-static local variable is ignored}}
+ static int y [[clang::internal_linkage]];
+}