[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