From 2f402708e62f89fb875442802e3d3f20fc909d33 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Fri, 26 Dec 2008 00:52:02 +0000 Subject: [PATCH] Add full dllimport / dllexport support: both sema checks and codegen. 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 | 12 ++++-- include/clang/Basic/DiagnosticKinds.def | 2 + lib/CodeGen/CodeGenModule.cpp | 27 ++++++++---- lib/Sema/SemaDecl.cpp | 28 +++++++++++-- lib/Sema/SemaDeclAttr.cpp | 56 +++++++++++++++++++++++++ test/CodeGen/dllimport-dllexport.c | 7 ++++ test/Sema/dllimmport-dllexport.c | 18 ++++++++ 7 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 test/CodeGen/dllimport-dllexport.c create mode 100644 test/Sema/dllimmport-dllexport.c diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 51f1e192af..1af49f186f 100644 --- a/include/clang/AST/Attr.h +++ b/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/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 5c72e8de39..2ffad9e8e4 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/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/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index e83d2cd293..fc1b108b0d 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/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()) - GV->setLinkage(llvm::Function::DLLImportLinkage); + if (D->getAttr()) { + // The dllimport attribute is overridden by a subsequent declaration as + // dllexport. + if (!D->getAttr()) + // dllimport attribute can be applied only to function decls, not to + // definitions. + if (const FunctionDecl *FD = dyn_cast(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()) - GV->setLinkage(llvm::Function::DLLImportLinkage); - else if (D->getAttr()) - GV->setLinkage(llvm::Function::DLLExportLinkage); - else if (D->getAttr() || IsInline) + if (D->getAttr()) { + if (const FunctionDecl *FD = dyn_cast(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() || IsInline) GV->setLinkage(llvm::Function::WeakLinkage); } } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 902101d617..bb0dd4d07c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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() && (!FD->getAttr())) { + // dllimport attribute cannot be applied to definition. + if (!(FD->getAttr())->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/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 81283a8560..759ef0950b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/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(d)) { + d->addAttr(new DLLImportAttr()); + return; + } + + FunctionDecl *FD = dyn_cast(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()) { + 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(d)) { + d->addAttr(new DLLExportAttr()); + return; + } + + FunctionDecl *FD = dyn_cast(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 index 0000000000..306f4ee26a --- /dev/null +++ b/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/test/Sema/dllimmport-dllexport.c b/test/Sema/dllimmport-dllexport.c new file mode 100644 index 0000000000..0f42ff388a --- /dev/null +++ b/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}} -- 2.40.0