diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3036,6 +3036,16 @@ let Documentation = [Undocumented]; } +def Linkage : InheritableAttr { + let Clone = 0; + let Spellings = [GCC<"linkage">]; + let Args = [EnumArgument<"Linkage", "LinkageType", + ["external", "available_externally", "linkonce", "linkonce_odr", "weak", "weak_odr", "appending", "internal", "private", "external_weak", "common"], + ["External", "AvailableExternally", "LinkOnceAny", "LinkOnceODR", "WeakAny", "WeakODR", "Appending", "Internal", "Private", "ExternalWeak", "Common"]>]; + let MeaningfulToClassTemplateDefinition = 1; + let Documentation = [Undocumented]; +} + def TypeVisibility : InheritableAttr { let Clone = 0; let Spellings = [Clang<"type_visibility">]; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5413,6 +5413,36 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(const DeclaratorDecl *D, GVALinkage Linkage) { + + if (const auto *A = D->getAttr()) { + switch (A->getLinkage()) { + case LinkageAttr::Private: + return llvm::GlobalValue::PrivateLinkage; + case LinkageAttr::Internal: + return llvm::GlobalValue::InternalLinkage; + case LinkageAttr::WeakAny: + return llvm::GlobalValue::WeakAnyLinkage; + case LinkageAttr::WeakODR: + return llvm::GlobalValue::WeakODRLinkage; + case LinkageAttr::LinkOnceAny: + return llvm::GlobalValue::LinkOnceAnyLinkage; + case LinkageAttr::LinkOnceODR: + return llvm::GlobalValue::LinkOnceODRLinkage; + case LinkageAttr::AvailableExternally: + return llvm::GlobalValue::AvailableExternallyLinkage; + case LinkageAttr::Appending: + return llvm::GlobalValue::AppendingLinkage; + case LinkageAttr::Common: + return llvm::GlobalValue::CommonLinkage; + case LinkageAttr::ExternalWeak: + return llvm::GlobalValue::ExternalWeakLinkage; + case LinkageAttr::External: + return llvm::GlobalValue::ExternalLinkage; + default: + llvm_unreachable("unknown linkage"); + } + } + if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2365,6 +2365,29 @@ D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); } +static void handleLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Linkage attributes don't mean anything on a typedef. + if (isa(D)) { + S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL; + return; + } + + // Check that the argument is a string literal. + StringRef TypeStr; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, TypeStr, &LiteralLoc)) + return; + + LinkageAttr::LinkageType type; + if (!LinkageAttr::ConvertStrToLinkageType(TypeStr, type)) { + S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) + << AL << TypeStr; + return; + } + + D->addAttr(::new (S.Context) LinkageAttr(S.Context, AL, type)); +} + static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { uint32_t priority = DestructorAttr::DefaultPriority; if (AL.getNumArgs() && @@ -8878,6 +8901,9 @@ S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl) << AL << AL.isRegularKeywordAttribute() << D->getLocation(); break; + case ParsedAttr::AT_Linkage: + handleLinkageAttr(S, D, AL); + break; case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); break; diff --git a/clang/test/CodeGen/attr-linkage.c b/clang/test/CodeGen/attr-linkage.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-linkage.c @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -emit-llvm -Wno-gcc-compat -O1 -disable-llvm-passes -o - %s | FileCheck %s + +int v01 __attribute__((linkage("external"))); +int v02 __attribute__((linkage("available_externally"))); +int v03 __attribute__((linkage("linkonce"))); +int v04 __attribute__((linkage("linkonce_odr"))); +int v05 __attribute__((linkage("weak"))); +int v06 __attribute__((linkage("weak_odr"))); +int v07[3] __attribute__((linkage("appending"))); +int v08 __attribute__((linkage("internal"))); +int v09 __attribute__((linkage("private"))); +int v10 __attribute__((linkage("external_weak"))); +int v11 __attribute__((linkage("common"))); + +// CHECK: @v01 = global i32 0 +// CHECK: @v02 = available_externally global i32 0 +// CHECK: @v03 = linkonce global i32 0 +// CHECK: @v04 = linkonce_odr global i32 0 +// CHECK: @v05 = weak global i32 0 +// CHECK: @v06 = weak_odr global i32 0 +// CHECK: @v07 = appending global [3 x i32] zeroinitializer +// CHECK: @v08 = internal global i32 0 +// CHECK: @v09 = private global i32 0 +// CHECK: @v10 = extern_weak global i32 0 +// CHECK: @v11 = common global i32 0 + +void f01(void) __attribute__((linkage("external"))) {}; +void f02(void) __attribute__((linkage("available_externally"))) {}; +void f03(void) __attribute__((linkage("linkonce"))) {}; +void f04(void) __attribute__((linkage("linkonce_odr"))) {}; +void f05(void) __attribute__((linkage("weak"))) {}; +void f06(void) __attribute__((linkage("weak_odr"))) {}; +// appending is only applicable to variables +void f08(void) __attribute__((linkage("internal"))) {}; +void f09(void) __attribute__((linkage("private"))) {}; +void f10(void) __attribute__((linkage("external_weak"))) {}; +// common is only applicable to variables + +// CHECK: define dso_local void @f01() +// CHECK: define available_externally void @f02() +// CHECK: define linkonce void @f03() +// CHECK: define linkonce_odr void @f04() +// CHECK: define weak void @f05() +// CHECK: define weak_odr void @f06() +// CHECK: define internal void @f08() +// CHECK: define private void @f09() +// CHECK: define extern_weak void @f10()