Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2249,3 +2249,9 @@ let Subjects = SubjectList<[Var, Function, CXXRecord]>; let Documentation = [InternalLinkageDocs]; } + +def LinkOnceODRLinkage : InheritableAttr { + let Spellings = [GNU<"linkonce_odr_linkage">]; + let Subjects = SubjectList<[Var, Function]>; + let Documentation = [LinkOnceODRLinkageDocs]; +} \ No newline at end of file Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -1924,6 +1924,13 @@ }]; } +def LinkOnceODRLinkageDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``linkonce_odr_linkage`` attribute changes the linkage type of the declaration to linkonce_odr. + }]; +} + def DisableTailCallsDocs : Documentation { let Category = DocCatFunction; let Content = [{ Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2144,6 +2144,10 @@ unsigned AttrSpellingListIndex); CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); + LinkOnceODRLinkageAttr * + mergeLinkOnceODRLinkageAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -752,7 +752,6 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getFunctionLinkage(GlobalDecl GD) { const auto *D = cast(GD.getDecl()); - GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); if (isa(D) && @@ -2626,6 +2625,9 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator( const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable) { + if (D->hasAttr()) + return llvm::GlobalVariable::LinkOnceODRLinkage; + if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -3611,6 +3611,19 @@ InternalLinkageAttr(Range, Context, AttrSpellingListIndex); } +LinkOnceODRLinkageAttr * +Sema::mergeLinkOnceODRLinkageAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex) { + if (checkAttrMutualExclusion(*this, D, Range, Ident) || + checkAttrMutualExclusion(*this, D, Range, Ident)) + return nullptr; + + return ::new (Context) LinkOnceODRLinkageAttr(Range, + Context, + AttrSpellingListIndex); +} + MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (OptimizeNoneAttr *Optnone = D->getAttr()) { @@ -5206,6 +5219,14 @@ D->addAttr(Internal); } +static void handleLinkOnceODRLinkageAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (LinkOnceODRLinkageAttr *LinkOnce = + S.mergeLinkOnceODRLinkageAttr(D, Attr.getRange(), Attr.getName(), + Attr.getAttributeSpellingListIndex())) + D->addAttr(LinkOnce); +} + /// 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. @@ -5701,6 +5722,8 @@ case AttributeList::AT_InternalLinkage: handleInternalLinkageAttr(S, D, Attr); break; + case AttributeList::AT_LinkOnceODRLinkage: + handleLinkOnceODRLinkageAttr(S, D, Attr); // Microsoft attributes: case AttributeList::AT_MSNoVTable: Index: test/CodeGen/attr-linkonce-odr-linkage.c =================================================================== --- /dev/null +++ test/CodeGen/attr-linkonce-odr-linkage.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu < %s | FileCheck %s + +// CHECK: @a = linkonce_odr global i32 0 +__attribute__((linkonce_odr_linkage)) int a; + +// CHECK: define linkonce_odr void @test1_g() +void test1_g(void) __attribute__((linkonce_odr_linkage)); + Index: test/Sema/attr-linkonce-odr-linkage.c =================================================================== --- /dev/null +++ test/Sema/attr-linkonce-odr-linkage.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +extern int g0 __attribute__((linkonce_odr_linkage)); +int g2 __attribute__((linkonce_odr_linkage)); +int __attribute__((linkonce_odr_linkage)) g4(void); +void __attribute__((linkonce_odr_linkage)) g5(void) { +} + +struct __attribute__((linkonce_odr_linkage)) s0 {}; // expected-warning {{'linkonce_odr_linkage' attribute only applies to variables and functions}} + +static int x __attribute__((linkonce_odr_linkage)); // expected-error {{weak declaration cannot have internal linkage}} + +int C; // expected-note {{previous definition is here}} +extern int C __attribute__((linkonce_odr_linkage)); // expected-warning {{an already-declared variable is made a weak_import declaration}} + +static int pr14946_x; +extern int pr14946_x __attribute__((linkonce_odr_linkage)); // expected-error {{weak declaration cannot have internal linkage}} + +static void pr14946_f(); +void pr14946_f() __attribute__((linkonce_odr_linkage)); // expected-error {{weak declaration cannot have internal linkage}}