[cfe-commits] [PATCH] Add support for Microsoft __declspec(selectany)
John Wiegley
johnw at boostpro.com
Tue Oct 11 15:47:58 PDT 2011
This patch authored by Eric Niebler.
---
include/clang/Basic/Attr.td | 4 ++
include/clang/Basic/DiagnosticSemaKinds.td | 3 ++
include/clang/Sema/AttributeList.h | 1 +
lib/CodeGen/CodeGenModule.cpp | 4 ++
lib/Sema/AttributeList.cpp | 1 +
lib/Sema/SemaDecl.cpp | 22 ++++++++++++
lib/Sema/SemaDeclAttr.cpp | 50 ++++++++++++++++++++++++++--
test/Sema/attr-selectany.c | 18 ++++++++++
test/SemaCXX/attr-selectany.cpp | 29 ++++++++++++++++
9 files changed, 129 insertions(+), 3 deletions(-)
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 2a4ba5c..ca1797c 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -511,6 +511,10 @@ def Pascal : InheritableAttr {
let Spellings = ["pascal", "__pascal"];
}
+def SelectAny : InheritableAttr {
+ let Spellings = ["selectany"];
+}
+
def TransparentUnion : InheritableAttr {
let Spellings = ["transparent_union"];
}
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c4e0168..2913397 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1367,6 +1367,9 @@ def err_attribute_section_invalid_for_target : Error<
"argument to 'section' attribute is not valid for this target: %0">;
def err_attribute_section_local_variable : Error<
"'section' attribute is not valid on local variables">;
+def err_attribute_selectany_invalid_for_target : Error<
+ "'selectany' attribute is only valid on the initialization of global data "
+ "with external linkage">;
def err_attribute_aligned_not_power_of_two : Error<
"requested alignment is not a power of 2">;
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index bcacf7a..de62ce9 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -250,6 +250,7 @@ public:
AT_reqd_wg_size,
AT_scoped_lockable,
AT_section,
+ AT_selectany,
AT_sentinel,
AT_shared,
AT_shared_lock_function,
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index aab513f..cf5d6a5 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1104,6 +1104,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
GV->setLinkage(llvm::GlobalValue::DLLImportLinkage);
else if (D->hasAttr<WeakAttr>() || D->isWeakImported())
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ else if (D->hasAttr<SelectAnyAttr>())
+ GV->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
// Set visibility on a declaration only if it's explicit.
if (LV.visibilityExplicit())
@@ -1413,6 +1415,8 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
return llvm::GlobalVariable::WeakODRLinkage;
else
return llvm::GlobalVariable::WeakAnyLinkage;
+ } else if (D->hasAttr<SelectAnyAttr>()) {
+ return llvm::GlobalValue::LinkOnceODRLinkage;
} else if (Linkage == GVA_TemplateInstantiation ||
Linkage == GVA_ExplicitTemplateInstantiation)
return llvm::GlobalVariable::WeakODRLinkage;
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 13a0ede..26be829 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -130,6 +130,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
.Case("objc_gc", AT_objc_gc)
.Case("regparm", AT_regparm)
.Case("section", AT_section)
+ .Case("selectany", AT_selectany)
.Case("stdcall", AT_stdcall)
.Case("annotate", AT_annotate)
.Case("fastcall", AT_fastcall)
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b1e4a4e..d960e68 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4233,6 +4233,21 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD,
Redeclaration = true;
MergeVarDecl(NewVD, Previous);
}
+
+ // Microsoft's __declspec(selectany) attribute can only be used on global
+ // variables with external linkage. The check for global-ness has already
+ // been performed in HandleSelectAnyAttr.
+ // If you move this elsewhere, please update the comment in HandleSelectAnyAttr.
+ if (NewVD->hasAttr<SelectAnyAttr>() &&
+ NewVD->getType().isConstQualified() &&
+ NewVD->getLinkage() != ExternalLinkage) {
+ if(Previous.empty() ||
+ Previous.getFoundDecl()->getLinkage() != ExternalLinkage) {
+ Diag(NewVD->getAttr<SelectAnyAttr>()->getLocation(), diag::err_attribute_selectany_invalid_for_target);
+ NewVD->setInvalidDecl();
+ return;
+ }
+ }
}
/// \brief Data used with FindOverriddenMethod
@@ -6078,6 +6093,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
diag::err_abstract_type_in_decl,
AbstractVariableType))
Var->setInvalidDecl();
+
+ // Use of Microsoft's __declspec(selectany) requires an initializer
+ // If you move this elsewhere, please update the comment in HandleSelectAnyAttr.
+ if (Var->hasAttr<SelectAnyAttr>()) {
+ Diag(Var->getLocation(), diag::err_attribute_selectany_invalid_for_target);
+ Var->setInvalidDecl();
+ }
return;
case VarDecl::TentativeDefinition:
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index f76bb58..9be7b22 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2013,6 +2013,40 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
SE->getString()));
}
+static void HandleSelectAnyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Attribute has no arguments.
+ if (Attr.getNumArgs() != 0) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+
+ // Can only apply selectany attribute to variable declarations
+ if (!isa<VarDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_selectany_invalid_for_target);
+ return;
+ }
+
+ VarDecl *VD = cast<VarDecl>(D);
+
+ // the selectany attribute can only be applied to the actual initialization of
+ // global declarations that are externally visible.
+ if (!VD->hasGlobalStorage()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_selectany_invalid_for_target);
+ return;
+ }
+
+ // The test for external linkage is done in Sema::CheckVariableDeclaration.
+ // That's to handle cases like:
+ // extern const int x4;
+ // const __declspec(selectany) int x4=4;
+ // where "extern" appears on a prior declaration.
+ //
+ // The test for an initializer is done in Sema::ActOnUninitializedDecl. We
+ // can't check for it here because the initializer has not been parsed yet.
+
+ D->addAttr(::new (S.Context) SelectAnyAttr(Attr.getLoc(), S.Context));
+}
+
static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
@@ -3406,9 +3440,16 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
}
static bool isKnownDeclSpecAttr(const AttributeList &Attr) {
- return Attr.getKind() == AttributeList::AT_dllimport ||
- Attr.getKind() == AttributeList::AT_dllexport ||
- Attr.getKind() == AttributeList::AT_uuid;
+ switch (Attr.getKind()) {
+ case AttributeList::AT_dllimport:
+ case AttributeList::AT_dllexport:
+ case AttributeList::AT_selectany:
+ case AttributeList::AT_uuid:
+ return true;
+ default:;
+ // pass, fall-through
+ }
+ return false;
}
//===----------------------------------------------------------------------===//
@@ -3633,6 +3674,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_opencl_kernel_function:
handleOpenCLKernelAttr(S, D, Attr);
break;
+ case AttributeList::AT_selectany:
+ HandleSelectAnyAttr(S, D, Attr);
+ break;
case AttributeList::AT_uuid:
handleUuidAttr(S, D, Attr);
break;
diff --git a/test/Sema/attr-selectany.c b/test/Sema/attr-selectany.c
new file mode 100644
index 0000000..f2f1365
--- /dev/null
+++ b/test/Sema/attr-selectany.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+//Correct - x1 is initialized and externally visible
+__declspec(selectany) int x1=1;
+
+//This is OK in C, since const is not by default static in C
+const __declspec(selectany) int x2 =2;
+
+//Correct - x3 is extern const, so externally visible
+extern const __declspec(selectany) int x3=3; // expected-warning{{'extern' variable has an initializer}}
+
+//Correct - x4 is extern const, so it is externally visible
+extern const int x4;
+const __declspec(selectany) int x4=4;
+
+//Incorrect - __declspec(selectany) is applied to the uninitialized
+//declaration of x5
+extern __declspec(selectany) int x5; // expected-error{{'selectany' attribute is only valid on the initialization of global data with external linkage}}
diff --git a/test/SemaCXX/attr-selectany.cpp b/test/SemaCXX/attr-selectany.cpp
new file mode 100644
index 0000000..46d4ddf
--- /dev/null
+++ b/test/SemaCXX/attr-selectany.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+//Correct - x1 is initialized and externally visible
+__declspec(selectany) int x1=1;
+
+//Incorrect - const is by default static in C++, so
+//x2 is not visible externally (This is OK in C, since
+//const is not by default static in C)
+const __declspec(selectany) int x2 =2; // expected-error{{'selectany' attribute is only valid on the initialization of global data with external linkage}}
+
+//Correct - x3 is extern const, so externally visible
+extern const __declspec(selectany) int x3=3;
+
+//Correct - x4 is extern const, so it is externally visible
+extern const int x4;
+const __declspec(selectany) int x4=4;
+
+//Incorrect - __declspec(selectany) is applied to the uninitialized
+//declaration of x5
+extern __declspec(selectany) int x5; // expected-error{{'selectany' attribute is only valid on the initialization of global data with external linkage}}
+
+// OK: dynamic initialization of global object
+class X {
+public:
+ X(int i){i++;};
+ int i;
+};
+
+__declspec(selectany) X x(1);
More information about the cfe-commits
mailing list