mirror of https://github.com/microsoft/clang.git
Implement __attribute__((internal_linkage)).
The attrubite is applicable to functions and variables and changes the linkage of the subject to internal. This is the same functionality as C-style "static", but applicable to class methods; and the same as anonymouns namespaces, but can apply to individual methods of a class. Following the proposal in http://lists.llvm.org/pipermail/cfe-dev/2015-October/045580.html git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@252648 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1ae6ec4574
commit
b964ad11c0
|
@ -2132,3 +2132,9 @@ def OMPThreadPrivateDecl : InheritableAttr {
|
|||
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];
|
||||
}
|
||||
|
|
|
@ -1666,6 +1666,15 @@ Marking virtual functions as ``not_tail_called`` is an error:
|
|||
// 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.
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -4085,6 +4085,12 @@ def warn_undefined_inline : Warning<"inline function %q0 is not defined">,
|
|||
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>;
|
||||
|
|
|
@ -2115,6 +2115,11 @@ public:
|
|||
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);
|
||||
|
|
|
@ -1217,6 +1217,10 @@ getOutermostEnclosingLambda(const CXXRecordDecl *Record) {
|
|||
|
||||
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()) {
|
||||
|
@ -1307,6 +1311,10 @@ class LinkageComputer {
|
|||
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);
|
||||
|
||||
|
|
|
@ -2216,6 +2216,15 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
|||
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 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
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) {
|
||||
|
|
|
@ -244,11 +244,12 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr,
|
|||
/// \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,7 +1524,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
}
|
||||
|
||||
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,
|
||||
|
@ -1531,7 +1532,7 @@ static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
}
|
||||
|
||||
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 handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
|||
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) {
|
||||
|
@ -1703,7 +1705,8 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
|
|||
|
||||
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(
|
||||
|
@ -3392,6 +3395,42 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
|
|||
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>()) {
|
||||
|
@ -3428,7 +3467,8 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
|
|||
|
||||
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(
|
||||
|
@ -4014,7 +4054,8 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
|
|||
|
||||
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)
|
||||
|
@ -4024,7 +4065,8 @@ static void handleCFAuditedTransferAttr(Sema &S, Decl *D,
|
|||
|
||||
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)
|
||||
|
@ -4646,6 +4688,14 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
|
|||
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.
|
||||
|
@ -5090,6 +5140,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
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:
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -6,5 +6,7 @@ int bar() __attribute__((__cold__));
|
|||
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}}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// 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();
|
||||
|
|
|
@ -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}}
|
|
@ -0,0 +1,47 @@
|
|||
// 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]];
|
||||
}
|
Loading…
Reference in New Issue