InGroup<IgnoredAttributes>;
def err_attribute_dll_redeclaration : Error<
"redeclaration of %q0 cannot add %q1 attribute">;
+def err_attribute_dllimport_function_definition : Error<
+ "dllimport cannot be applied to non-inline function definition">;
def err_attribute_dllimport_data_definition : Error<
"definition of dllimport data">;
def err_attribute_weakref_not_static : Error<
return getFunctionType(ResType, ArgTypes, EPI);
}
-GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
+static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
+ const FunctionDecl *FD) {
if (!FD->isExternallyVisible())
return GVA_Internal;
if (!FD->isInlined())
return External;
- if ((!getLangOpts().CPlusPlus && !getLangOpts().MSVCCompat) ||
+ if ((!Context.getLangOpts().CPlusPlus && !Context.getLangOpts().MSVCCompat &&
+ !FD->hasAttr<DLLExportAttr>()) ||
FD->hasAttr<GNUInlineAttr>()) {
+ // FIXME: This doesn't match gcc's behavior for dllexport inline functions.
+
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
if (FD->isInlineDefinitionExternallyVisible())
return GVA_DiscardableODR;
}
-GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+static GVALinkage adjustGVALinkageForDLLAttribute(GVALinkage L, const Decl *D) {
+ // See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx
+ // dllexport/dllimport on inline functions.
+ if (D->hasAttr<DLLImportAttr>()) {
+ if (L == GVA_DiscardableODR || L == GVA_StrongODR)
+ return GVA_AvailableExternally;
+ } else if (D->hasAttr<DLLExportAttr>()) {
+ if (L == GVA_DiscardableODR)
+ return GVA_StrongODR;
+ }
+ return L;
+}
+
+GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
+ return adjustGVALinkageForDLLAttribute(basicGVALinkageForFunction(*this, FD),
+ FD);
+}
+
+static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
+ const VarDecl *VD) {
if (!VD->isExternallyVisible())
return GVA_Internal;
// enclosing function.
if (LexicalContext)
StaticLocalLinkage =
- GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
+ Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
// GVA_StrongODR function linkage is stronger than what we need,
// downgrade to GVA_DiscardableODR.
// Itanium-specified entry point, which has the normal linkage of the
// variable.
if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
- getTargetInfo().getTriple().isMacOSX())
+ Context.getTargetInfo().getTriple().isMacOSX())
return GVA_Internal;
switch (VD->getTemplateSpecializationKind()) {
llvm_unreachable("Invalid Linkage!");
}
+GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+ return adjustGVALinkageForDLLAttribute(basicGVALinkageForVariable(*this, VD),
+ VD);
+}
+
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
assert(isInlined() && "expected to get called on an inlined function!");
const ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().MSVCCompat)
+ if (!Context.getLangOpts().MSVCCompat && !hasAttr<DLLExportAttr>())
return false;
for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDecl())
if (Linkage == GVA_AvailableExternally)
return llvm::Function::AvailableExternallyLinkage;
- // LinkOnceODRLinkage is insufficient if the symbol is required to exist in
- // the symbol table. Promote the linkage to WeakODRLinkage to preserve the
- // semantics of LinkOnceODRLinkage while providing visibility in the symbol
- // table.
- llvm::GlobalValue::LinkageTypes OnceLinkage =
- llvm::GlobalValue::LinkOnceODRLinkage;
- if (D->hasAttr<DLLExportAttr>() || D->hasAttr<DLLImportAttr>())
- OnceLinkage = llvm::GlobalVariable::WeakODRLinkage;
-
// Note that Apple's kernel linker doesn't support symbol
// coalescing, so we need to avoid linkonce and weak linkages there.
// Normally, this means we just map to internal, but for explicit
// merged with other definitions. c) C++ has the ODR, so we know the
// definition is dependable.
if (Linkage == GVA_DiscardableODR)
- return !Context.getLangOpts().AppleKext ? OnceLinkage
+ return !Context.getLangOpts().AppleKext ? llvm::Function::LinkOnceODRLinkage
: llvm::Function::InternalLinkage;
// An explicit instantiation of a template has weak linkage, since
// Destructor variants in the Microsoft C++ ABI are always linkonce_odr thunks
// emitted on an as-needed basis.
if (UseThunkForDtorVariant)
- return OnceLinkage;
+ return llvm::GlobalValue::LinkOnceODRLinkage;
// If required by the ABI, give definitions of static data members with inline
// initializers at least linkonce_odr linkage.
if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
isa<VarDecl>(D) &&
isVarDeclInlineInitializedStaticDataMember(cast<VarDecl>(D)))
- return OnceLinkage;
+ return llvm::GlobalValue::LinkOnceODRLinkage;
// C++ doesn't have tentative definitions and thus cannot have common
// linkage.
if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>())
ResolveExceptionSpec(D->getLocation(), FPT);
- // Checking attributes of current function definition
- // dllimport attribute.
- DLLImportAttr *DA = FD->getAttr<DLLImportAttr>();
- if (DA && (!FD->hasAttr<DLLExportAttr>())) {
- // dllimport attribute cannot be directly applied to definition.
- // Microsoft accepts dllimport for functions defined within class scope.
- if (!DA->isInherited() &&
- !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) {
- Diag(FD->getLocation(),
- diag::err_attribute_can_be_applied_only_to_symbol_declaration)
- << DA;
- FD->setInvalidDecl();
- return D;
- }
+ // dllimport cannot be applied to non-inline function definitions.
+ if (FD->hasAttr<DLLImportAttr>() && !FD->isInlined()) {
+ assert(!FD->hasAttr<DLLExportAttr>());
+ Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition);
+ FD->setInvalidDecl();
+ return D;
}
// We want to attach documentation to original Decl (which might be
// a function template).
return;
}
- // Currently, the dllimport attribute is ignored for inlined functions.
- // Warning is emitted.
- if (FD && FD->isInlineSpecified()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
- return;
- }
-
unsigned Index = Attr.getAttributeSpellingListIndex();
DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
if (NewAttr)
}
static void handleDLLExportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Currently, the dllexport attribute is ignored for inlined functions, unless
- // the -fkeep-inline-functions flag has been used. Warning is emitted.
- if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isInlineSpecified()) {
- // FIXME: ... unless the -fkeep-inline-functions flag has been used.
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
- return;
- }
-
unsigned Index = Attr.getAttributeSpellingListIndex();
DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
if (NewAttr)
--- /dev/null
+// RUN: %clang_cc1 -triple i686-pc-win32 -std=c99 -O2 -disable-llvm-optzns -emit-llvm < %s | FileCheck %s
+
+#define DLLEXPORT __declspec(dllexport)
+
+inline void DLLEXPORT f() {}
+extern void DLLEXPORT f();
+
+// CHECK: define weak_odr dllexport void @f()
--- /dev/null
+// RUN: %clang_cc1 -triple i686-pc-win32 -x c++ -O2 -disable-llvm-optzns -emit-llvm < %s | FileCheck %s
+
+#define DLLEXPORT __declspec(dllexport)
+
+void DLLEXPORT a();
+// CHECK-DAG: declare dllexport void @"\01?a@@YAXXZ"()
+
+inline void DLLEXPORT b() {}
+// CHECK-DAG: define weak_odr dllexport void @"\01?b@@YAXXZ"()
+
+template <typename T> void c() {}
+template void DLLEXPORT c<int>();
+// CHECK-DAG: define weak_odr dllexport void @"\01??$c@H@@YAXXZ"()
+
+struct S {
+ void DLLEXPORT a() {}
+ // CHECK-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a@S@@QAEXXZ"
+};
+
+void user() {
+ // FIXME: dllexported functions must be emitted even if they're not referenced in this TU.
+ a();
+ b();
+ &S::a;
+}
--- /dev/null
+// RUN: %clang_cc1 -triple i686-pc-win32 -x c++ -O2 -disable-llvm-optzns -emit-llvm < %s | FileCheck %s
+
+#define DLLIMPORT __declspec(dllimport)
+
+void DLLIMPORT a();
+// CHECK-DAG: declare dllimport void @"\01?a@@YAXXZ"()
+
+inline void DLLIMPORT b() {}
+// CHECK-DAG: define available_externally dllimport void @"\01?b@@YAXXZ"()
+
+template <typename T> inline void c() {} // FIXME: MSVC accepts this without 'inline' too.
+template void DLLIMPORT c<int>();
+// CHECK-DAG: define available_externally dllimport void @"\01??$c@H@@YAXXZ"()
+
+struct S {
+ void DLLIMPORT a() {}
+ // CHECK-DAG: define available_externally dllimport x86_thiscallcc void @"\01?a@S@@QAEXXZ"
+};
+
+void user(S* s) {
+ a();
+ b();
+ c<int>();
+ s->a();
+}
__declspec(dllexport) void def() {}
// Export inline function.
-__declspec(dllexport) inline void inlineFunc1() {} // expected-warning{{'dllexport' attribute ignored}}
+__declspec(dllexport) inline void inlineFunc1() {}
extern void inlineFunc1();
-inline void __attribute__((dllexport)) inlineFunc2() {} // expected-warning{{'dllexport' attribute ignored}}
+inline void __attribute__((dllexport)) inlineFunc2() {}
extern void inlineFunc2();
// Redeclarations
void __declspec(dllimport) decl2B();
// Not allowed on function definitions.
-__declspec(dllimport) void def() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}}
+__declspec(dllimport) void def() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
// Import inline function.
-__declspec(dllimport) inline void inlineFunc1() {} // expected-warning{{'dllimport' attribute ignored}}
-inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dllimport' attribute ignored}}
+__declspec(dllimport) inline void inlineFunc1() {}
+inline void __attribute__((dllimport)) inlineFunc2() {}
// Redeclarations
__declspec(dllimport) void redecl1();
void f2(void); // expected-note{{previous declaration is here}}
};
-__declspec(dllimport) void AAA::f2(void) { // expected-error{{'dllimport' attribute can be applied only to symbol}}
+__declspec(dllimport) void AAA::f2(void) { // expected-error{{dllimport cannot be applied to non-inline function definition}}
// expected-error@-1{{redeclaration of 'AAA::f2' cannot add 'dllimport' attribute}}
}
extern "C" __declspec(dllexport) void externC() {}
// Export inline function.
-__declspec(dllexport) inline void inlineFunc1() {} // expected-warning{{'dllexport' attribute ignored}}
-inline void __attribute__((dllexport)) inlineFunc2() {} // expected-warning{{'dllexport' attribute ignored}}
+__declspec(dllexport) inline void inlineFunc1() {}
+inline void __attribute__((dllexport)) inlineFunc2() {}
-__declspec(dllexport) inline void inlineDecl(); // expected-warning{{'dllexport' attribute ignored}}
+__declspec(dllexport) inline void inlineDecl();
void inlineDecl() {}
__declspec(dllexport) void inlineDef();
// Export specialization of an exported function template.
template<> __declspec(dllexport) void exportedFuncTmpl<ExplicitSpec_Exported>();
template<> __declspec(dllexport) void exportedFuncTmpl<ExplicitSpec_Def_Exported>() {}
-template<> __declspec(dllexport) inline void exportedFuncTmpl<ExplicitSpec_InlineDef_Exported>() {} // expected-warning{{'dllexport' attribute ignored}}
+template<> __declspec(dllexport) inline void exportedFuncTmpl<ExplicitSpec_InlineDef_Exported>() {}
// Not exporting specialization of an exported function template without
// explicit dllexport.
// Export specialization of a non-exported function template.
template<> __declspec(dllexport) void funcTmpl<ExplicitSpec_Exported>();
template<> __declspec(dllexport) void funcTmpl<ExplicitSpec_Def_Exported>() {}
-template<> __declspec(dllexport) inline void funcTmpl<ExplicitSpec_InlineDef_Exported>() {} // expected-warning{{'dllexport' attribute ignored}}
+template<> __declspec(dllexport) inline void funcTmpl<ExplicitSpec_InlineDef_Exported>() {}
void __declspec(dllimport) decl2B();
// Not allowed on function definitions.
-__declspec(dllimport) void def() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}}
+__declspec(dllimport) void def() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
// extern "C"
extern "C" __declspec(dllexport) void externC();
// Import inline function.
-__declspec(dllimport) inline void inlineFunc1() {} // expected-warning{{'dllimport' attribute ignored}}
-inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dllimport' attribute ignored}}
+__declspec(dllimport) inline void inlineFunc1() {}
+inline void __attribute__((dllimport)) inlineFunc2() {}
// Redeclarations
__declspec(dllimport) void redecl1();
// Import specialization of an imported function template. A definition must be
// declared inline.
template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Imported>();
-template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}}
-template<> __declspec(dllimport) inline void importedFuncTmpl<ExplicitSpec_InlineDef_Imported>() {} // expected-warning{{'dllimport' attribute ignored}}
+template<> __declspec(dllimport) void importedFuncTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+template<> __declspec(dllimport) inline void importedFuncTmpl<ExplicitSpec_InlineDef_Imported>() {}
// Not importing specialization of an imported function template without
// explicit dllimport.
// Import specialization of a non-imported function template. A definition must
// be declared inline.
template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Imported>();
-template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}}
-template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {} // expected-warning{{'dllimport' attribute ignored}}
+template<> __declspec(dllimport) void funcTmpl<ExplicitSpec_Def_Imported>() {} // expected-error{{dllimport cannot be applied to non-inline function definition}}
+template<> __declspec(dllimport) inline void funcTmpl<ExplicitSpec_InlineDef_Imported>() {}