diff options
author | Anton Korobeynikov <asl@math.spbu.ru> | 2008-12-26 00:52:02 +0000 |
---|---|---|
committer | Anton Korobeynikov <asl@math.spbu.ru> | 2008-12-26 00:52:02 +0000 |
commit | d72f47aa058c10248c27ea70074a1bdd91468a1b (patch) | |
tree | f902ea37a85333ff29f0dd91d7f43a1950308f58 | |
parent | 3112c877c150d2aea6427098ed6f0d805eb28079 (diff) | |
download | bcm5719-llvm-d72f47aa058c10248c27ea70074a1bdd91468a1b.tar.gz bcm5719-llvm-d72f47aa058c10248c27ea70074a1bdd91468a1b.zip |
Add full dllimport / dllexport support: both sema checks and codegen.
Patch by Ilya Okonsky
llvm-svn: 61437
-rw-r--r-- | clang/include/clang/AST/Attr.h | 12 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 27 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 56 | ||||
-rw-r--r-- | clang/test/CodeGen/dllimport-dllexport.c | 7 | ||||
-rw-r--r-- | clang/test/Sema/dllimmport-dllexport.c | 18 |
7 files changed, 135 insertions, 15 deletions
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 51f1e192af8..1af49f186f0 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -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"); diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 5c72e8de39e..2ffad9e8e42 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -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, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index e83d2cd2930..fc1b108b0d6 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -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); } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 902101d617c..bb0dd4d07cf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 81283a85606..759ef0950b5 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -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/clang/test/CodeGen/dllimport-dllexport.c b/clang/test/CodeGen/dllimport-dllexport.c new file mode 100644 index 00000000000..306f4ee26ab --- /dev/null +++ b/clang/test/CodeGen/dllimport-dllexport.c @@ -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/clang/test/Sema/dllimmport-dllexport.c b/clang/test/Sema/dllimmport-dllexport.c new file mode 100644 index 00000000000..0f42ff388aa --- /dev/null +++ b/clang/test/Sema/dllimmport-dllexport.c @@ -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}} |