]> granicus.if.org Git - clang/commitdiff
Add full dllimport / dllexport support: both sema checks and codegen.
authorAnton Korobeynikov <asl@math.spbu.ru>
Fri, 26 Dec 2008 00:52:02 +0000 (00:52 +0000)
committerAnton Korobeynikov <asl@math.spbu.ru>
Fri, 26 Dec 2008 00:52:02 +0000 (00:52 +0000)
Patch by Ilya Okonsky

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61437 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Attr.h
include/clang/Basic/DiagnosticKinds.def
lib/CodeGen/CodeGenModule.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGen/dllimport-dllexport.c [new file with mode: 0644]
test/Sema/dllimmport-dllexport.c [new file with mode: 0644]

index 51f1e192af8b7b35154970636aee4e1baa59aa82..1af49f186f0230845cbcb943fc961369bc4a593e 100644 (file)
@@ -57,16 +57,17 @@ public:
 private:
   Attr *Next;
   Kind AttrKind;
-  
+  bool Inherited : 1;
+
 protected:
-  Attr(Kind AK) : Next(0), AttrKind(AK) {}
+  Attr(Kind AK) : Next(0), AttrKind(AK), Inherited(false) {}
 public:
   virtual ~Attr() {
     delete Next;
   }
 
   Kind getKind() const { return AttrKind; }
-  
+
   bool hasKind(Kind kind) const {
     return AttrKind == kind;
   }
@@ -74,7 +75,10 @@ public:
   Attr *getNext() { return Next; }
   const Attr *getNext() const { return Next; }
   void setNext(Attr *next) { Next = next; }
-  
+
+  bool isInherited() const { return Inherited; }
+  void setInherited(bool value) { Inherited = value; }
+
   void addAttr(Attr *attr) {
     assert((attr != 0) && "addAttr(): attr is null");
     
index 5c72e8de39eaae2fc8929cc81b59327e3cdacf83..2ffad9e8e42372ef22dd38dd517aab3abfdefb8f 100644 (file)
@@ -803,6 +803,8 @@ DIAG(err_objc_decls_may_only_appear_in_global_scope, ERROR,
      "Objective-C declarations may only appear in global scope")
 
 // Attributes
+DIAG(err_attribute_can_be_applied_only_to_symbol_declaration, ERROR,
+     "%0 attribute can be applied only to symbol declaration")
 DIAG(err_attributes_are_not_compatible, ERROR,
      "%0 and %1 attributes are not compatible")
 DIAG(err_attribute_wrong_number_arguments, ERROR,
index e83d2cd293016a40f77cf9319aca177a2bb97e6e..fc1b108b0d6e722bb5abfe4801f819d2c397276e 100644 (file)
@@ -218,17 +218,30 @@ static void SetGlobalValueAttributes(const Decl *D,
   // approximation of what we really want.
   if (!ForDefinition) {
     // Only a few attributes are set on declarations.
-    if (D->getAttr<DLLImportAttr>())
-      GV->setLinkage(llvm::Function::DLLImportLinkage);
+    if (D->getAttr<DLLImportAttr>()) {
+      // The dllimport attribute is overridden by a subsequent declaration as
+      // dllexport.
+      if (!D->getAttr<DLLExportAttr>())
+        // dllimport attribute can be applied only to function decls, not to
+        // definitions.
+        if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+          if (!FD->getBody())
+            GV->setLinkage(llvm::Function::DLLImportLinkage);
+        } else
+          GV->setLinkage(llvm::Function::DLLImportLinkage);
+    }
   } else {
     if (IsInternal) {
       GV->setLinkage(llvm::Function::InternalLinkage);
     } else {
-      if (D->getAttr<DLLImportAttr>())
-        GV->setLinkage(llvm::Function::DLLImportLinkage);
-      else if (D->getAttr<DLLExportAttr>())
-        GV->setLinkage(llvm::Function::DLLExportLinkage);
-      else if (D->getAttr<WeakAttr>() || IsInline)
+      if (D->getAttr<DLLExportAttr>()) {
+        if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+          // The dllexport attribute is ignored for undefined symbols.
+          if (FD->getBody())
+            GV->setLinkage(llvm::Function::DLLExportLinkage);
+        } else
+          GV->setLinkage(llvm::Function::DLLExportLinkage);
+      } else if (D->getAttr<WeakAttr>() || IsInline)
         GV->setLinkage(llvm::Function::WeakLinkage);
     }
   }
index 902101d617cf8c44988295693643446094644180..bb0dd4d07cf0ca8041a7695c997e822601d6146c 100644 (file)
@@ -509,6 +509,7 @@ static void MergeAttributes(Decl *New, Decl *Old) {
      attr = attr->getNext();
 
     if (!DeclHasAttr(New, tmp)) {
+       tmp->setInherited(true);
        New->addAttr(tmp);
     } else {
        tmp->setNext(0);
@@ -1207,9 +1208,6 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
                                    D.getDeclSpec().getSourceRange().getBegin());
     }
 
-    // Handle attributes.
-    ProcessDeclAttributes(NewFD, D);
-
     // Set the lexical context. If the declarator has a C++
     // scope specifier, the lexical context will be different
     // from the semantic context.
@@ -1386,6 +1384,9 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
         PrevDecl = 0;
       }
     }
+    // Handle attributes. We need to have merged decls when handling attributes
+    // (for example to check for conflicts, etc).
+    ProcessDeclAttributes(NewFD, D);
     New = NewFD;
 
     if (getLangOptions().CPlusPlus) {
@@ -2410,7 +2411,7 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
   }
 
   PushDeclContext(FnBodyScope, FD);
-    
+
   // Check the validity of our function parameters
   CheckParmsForFunctionDef(FD);
 
@@ -2422,6 +2423,25 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) {
       PushOnScopeChains(Param, FnBodyScope);
   }
 
+  // Checking attributes of current function definition
+  // dllimport attribute.
+  if (FD->getAttr<DLLImportAttr>() && (!FD->getAttr<DLLExportAttr>())) {
+    // dllimport attribute cannot be applied to definition.
+    if (!(FD->getAttr<DLLImportAttr>())->isInherited()) {
+      Diag(FD->getLocation(),
+           diag::err_attribute_can_be_applied_only_to_symbol_declaration)
+        << "dllimport";
+      FD->setInvalidDecl();
+      return FD;
+    } else {
+      // If a symbol previously declared dllimport is later defined, the
+      // attribute is ignored in subsequent references, and a warning is
+      // emitted.
+      Diag(FD->getLocation(),
+           diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
+        << FD->getNameAsCString() << "dllimport";
+    }
+  }
   return FD;
 }
 
index 81283a85606b196b5e7bb53f0452fa1a37fca587..759ef0950b54ff0f89bcef0080fece79918b0816 100644 (file)
@@ -685,6 +685,41 @@ static void HandleDLLImportAttr(Decl *d, const AttributeList &Attr, Sema &S) {
     return;
   }
 
+  // Attribute can be applied only to functions or variables.
+  if (isa<VarDecl>(d)) {
+    d->addAttr(new DLLImportAttr());
+    return;
+  }
+
+  FunctionDecl *FD = dyn_cast<FunctionDecl>(d);
+  if (!FD) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << "dllimport" << "function or variable";
+    return;
+  }
+
+  // Currently, the dllimport attribute is ignored for inlined functions.
+  // Warning is emitted.
+  if (FD->isInline()) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+    return;
+  }
+
+  // The attribute is also overridden by a subsequent declaration as dllexport.
+  // Warning is emitted.
+  for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
+       nextAttr = nextAttr->getNext()) {
+    if (nextAttr->getKind() == AttributeList::AT_dllexport) {
+      S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+      return;
+    }
+  }
+
+  if (d->getAttr<DLLExportAttr>()) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
+    return;
+  }
+
   d->addAttr(new DLLImportAttr());
 }
 
@@ -695,6 +730,27 @@ static void HandleDLLExportAttr(Decl *d, const AttributeList &Attr, Sema &S) {
     return;
   }
 
+  // Attribute can be applied only to functions or variables.
+  if (isa<VarDecl>(d)) {
+    d->addAttr(new DLLExportAttr());
+    return;
+  }
+
+  FunctionDecl *FD = dyn_cast<FunctionDecl>(d);
+  if (!FD) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+      << "dllexport" << "function or variable";
+    return;
+  }
+
+  // Currently, the dllexport attribute is ignored for inlined functions,
+  // unless the -fkeep-inline-functions flag has been used. Warning is emitted;
+  if (FD->isInline()) {
+    // FIXME: ... unless the -fkeep-inline-functions flag has been used.
+    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
+    return;
+  }
+
   d->addAttr(new DLLExportAttr());
 }
 
diff --git a/test/CodeGen/dllimport-dllexport.c b/test/CodeGen/dllimport-dllexport.c
new file mode 100644 (file)
index 0000000..306f4ee
--- /dev/null
@@ -0,0 +1,7 @@
+// RUN: clang -emit-llvm < %s -o %t &&
+// RUN: grep 'dllexport' %t | count 1 &&
+// RUN: not grep 'dllimport' %t
+
+void __attribute__((dllimport)) foo1();
+void __attribute__((dllexport)) foo1(){}
+void __attribute__((dllexport)) foo2();
diff --git a/test/Sema/dllimmport-dllexport.c b/test/Sema/dllimmport-dllexport.c
new file mode 100644 (file)
index 0000000..0f42ff3
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: clang -fsyntax-only -verify %s
+
+inline void __attribute__((dllexport)) foo1(){} // expected-warning{{dllexport attribute ignored}}
+inline void __attribute__((dllimport)) foo2(){} // expected-warning{{dllimport attribute ignored}}
+
+void __attribute__((dllimport)) foo3(){} // expected-error{{dllimport attribute can be applied only to symbol declaration}}
+
+void __attribute__((dllimport, dllexport)) foo4(); // expected-warning{{dllimport attribute ignored}}
+
+void __attribute__((dllexport)) foo5();
+void __attribute__((dllimport)) foo5(); // expected-warning{{dllimport attribute ignored}}
+
+typedef int __attribute__((dllexport)) type6; // expected-warning{{'dllexport' attribute only applies to function or variable types}}
+
+typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to function or variable}}
+
+void __attribute__((dllimport)) foo6();
+void foo6(){} // expected-warning {{'foo6' redeclared without dllimport attribute: previous dllimport ignored}}