Index: cfe/trunk/cfe/trunk/include/clang/AST/DeclCXX.h =================================================================== --- cfe/trunk/cfe/trunk/include/clang/AST/DeclCXX.h +++ cfe/trunk/cfe/trunk/include/clang/AST/DeclCXX.h @@ -734,6 +734,20 @@ return method_iterator(decls_end()); } + /// Iterator access to static data members. The static data iterator visits + /// all static data members of the class. + typedef specific_decl_iterator static_data_iterator; + + /// static_data_begin - Static data member begin iterator. Iterates in the + /// order the static data members were declared. + static_data_iterator static_data_begin() const { + return static_data_iterator(decls_begin()); + } + /// static_data_end - Static data member end iterator. + static_data_iterator static_data_end() const { + return static_data_iterator(decls_end()); + } + /// Iterator access to constructor members. typedef specific_decl_iterator ctor_iterator; Index: cfe/trunk/cfe/trunk/include/clang/Basic/DiagnosticGroups.td =================================================================== --- cfe/trunk/cfe/trunk/include/clang/Basic/DiagnosticGroups.td +++ cfe/trunk/cfe/trunk/include/clang/Basic/DiagnosticGroups.td @@ -527,6 +527,7 @@ // A warning group for warnings about Microsoft extensions. def Microsoft : DiagGroup<"microsoft">; +def MissingDLLExport : DiagGroup<"missing-dllexport">; def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">; Index: cfe/trunk/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -1751,7 +1751,24 @@ def err_nsobject_attribute : Error< "__attribute ((NSObject)) is for pointer types only">; def err_attribute_can_be_applied_only_to_symbol_declaration : Error< - "%0 attribute can be applied only to symbol declaration">; + "%0 attribute can be applied only to symbol declarations">; +def err_attribute_dllimpexp_not_extern_linkage : Error< + "%0 must have external linkage to be %select{imported|exported}1">; +def err_attribute_dllimpexp_redeclaration : Error< + "%0 redeclared with different DLL attributes">; +def err_attribute_dllimpexp_member_attr_not_allowed : Error< + "member of %select{imported|exported}0 class may not be declared with " + "%select{dllimport|dllexport}1 attribute">; +def err_attribute_dllimport_definition : Error< + "'dllimport' attribute cannot be specified on a definition">; +def err_attribute_dllimport_static_field_definition : Error< + "definition of 'dllimport' static field not allowed">; +def warn_attribute_dllexport_base_class : Warning< + "%0 is a base of an exported type and should be exported">, + InGroup, DefaultIgnore; +def warn_attribute_dllexport_accessible_type : Warning< + "%0 is accessible from exported type and should be exported">, + InGroup, DefaultIgnore; def err_attributes_are_not_compatible : Error< "%0 and %1 attributes are not compatible">; def err_attribute_wrong_number_arguments : Error< @@ -1940,7 +1957,9 @@ def err_attribute_aligned_greater_than_8192 : Error< "requested alignment must be 8192 bytes or smaller">; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< - "'%0' redeclared without %1 attribute: previous %1 ignored">; + "%q0 redeclared without %1 attribute: previous %1 ignored">; +def err_redeclaration_with_attribute : Error< + "cannot redeclare '%0' with %1 attribute">; def warn_attribute_ignored : Warning<"%0 attribute ignored">, InGroup; def warn_attribute_after_definition_ignored : Warning< Index: cfe/trunk/cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/cfe/trunk/lib/AST/ASTContext.cpp @@ -7894,7 +7894,11 @@ // Constructors and destructors are required. if (FD->hasAttr() || FD->hasAttr()) return true; - + + // Exported functions are required. + if (D->hasAttr()) + return true; + // The key function for a class is required. This rule only comes // into play when inline functions can be key functions, though. if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { Index: cfe/trunk/cfe/trunk/lib/AST/Decl.cpp =================================================================== --- cfe/trunk/cfe/trunk/lib/AST/Decl.cpp +++ cfe/trunk/cfe/trunk/lib/AST/Decl.cpp @@ -1690,6 +1690,10 @@ if (hasInit()) return Definition; + // A variable with the dllimport attribute implies a declaration. + if (hasAttr()) + return DeclarationOnly; + if (hasExternalStorage()) return DeclarationOnly; Index: cfe/trunk/cfe/trunk/lib/CodeGen/CGRTTI.cpp =================================================================== --- cfe/trunk/cfe/trunk/lib/CodeGen/CGRTTI.cpp +++ cfe/trunk/cfe/trunk/lib/CodeGen/CGRTTI.cpp @@ -129,6 +129,9 @@ GV->setInitializer(Init); + if (const RecordType *Record = dyn_cast(Ty)) + CGM.setDLLStorageClass(GV, cast(Record->getDecl()), Linkage); + return GV; } @@ -149,7 +152,10 @@ /*Constant=*/true, llvm::GlobalValue::ExternalLinkage, 0, Name); } - + + if (const RecordType *Record = dyn_cast(Ty)) + CGM.setDLLStorageClass(GV, cast(Record->getDecl())); + return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy); } @@ -670,6 +676,9 @@ GV->setUnnamedAddr(true); + if (const RecordType *Record = dyn_cast(Ty)) + CGM.setDLLStorageClass(GV, cast(Record->getDecl()), Linkage); + return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy); } Index: cfe/trunk/cfe/trunk/lib/CodeGen/CGVTT.cpp =================================================================== --- cfe/trunk/cfe/trunk/lib/CodeGen/CGVTT.cpp +++ cfe/trunk/cfe/trunk/lib/CodeGen/CGVTT.cpp @@ -117,6 +117,8 @@ CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, llvm::GlobalValue::ExternalLinkage); GV->setUnnamedAddr(true); + CGM.setDLLStorageClass(GV, RD); + return GV; } Index: cfe/trunk/cfe/trunk/lib/CodeGen/CGVTables.cpp =================================================================== --- cfe/trunk/cfe/trunk/lib/CodeGen/CGVTables.cpp +++ cfe/trunk/cfe/trunk/lib/CodeGen/CGVTables.cpp @@ -636,6 +636,8 @@ CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, llvm::GlobalValue::ExternalLinkage); VTable->setUnnamedAddr(true); + CGM.setDLLStorageClass(VTable, RD); + return VTable; } @@ -653,10 +655,10 @@ VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks()); VTable->setInitializer(Init); - + // Set the correct linkage. VTable->setLinkage(Linkage); - + // Set the right visibility. CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForVTable); } @@ -711,7 +713,9 @@ VTLayout->vtable_thunk_begin(), VTLayout->getNumVTableThunks()); VTable->setInitializer(Init); - + + CGM.setDLLStorageClass(VTable, RD, Linkage); + return VTable; } Index: cfe/trunk/lib/CodeGen/CodeGenModule.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h +++ cfe/trunk/lib/CodeGen/CodeGenModule.h @@ -569,6 +569,10 @@ void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D, TypeVisibilityKind TVK) const; + void setDLLStorageClass(llvm::GlobalVariable *GV, const CXXRecordDecl *D, + llvm::GlobalVariable::LinkageTypes Linkage); + void setDLLStorageClass(llvm::GlobalVariable *GV, const CXXRecordDecl *D); + static llvm::GlobalValue::VisibilityTypes GetLLVMVisibility(Visibility V) { switch (V) { case DefaultVisibility: return llvm::GlobalValue::DefaultVisibility; Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp @@ -413,6 +413,49 @@ GV->setUnnamedAddr(true); } +void CodeGenModule::setDLLStorageClass(llvm::GlobalVariable *GV, + const CXXRecordDecl *RD) { + llvm::GlobalVariable::LinkageTypes Linkage = getVTableLinkage(RD); + setDLLStorageClass(GV, RD, Linkage); +} + +void CodeGenModule::setDLLStorageClass(llvm::GlobalVariable *GV, + const CXXRecordDecl *RD, + llvm::GlobalVariable::LinkageTypes Linkage) { + bool Set = false; + + // Set the appropriate storage class for a dllimported/dllexported record only + // if we have external linkage. Otherwise the vtable is local. + if (Linkage == llvm::GlobalVariable::ExternalLinkage || + Linkage == llvm::GlobalVariable::AvailableExternallyLinkage) { + Set = true; + } + + switch (RD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + break; + + case TSK_ExplicitInstantiationDefinition: + Set = true; + break; + case TSK_ExplicitInstantiationDeclaration: + Set = true; + break; + + case TSK_ExplicitSpecialization: + break; + case TSK_ImplicitInstantiation: + break; + } + + if (Set) { + if (RD->hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); + else if (RD->hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); + } +} + StringRef CodeGenModule::getMangledName(GlobalDecl GD) { const NamedDecl *ND = cast(GD.getDecl()); @@ -520,13 +563,13 @@ if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; - - if (D->hasAttr()) - return llvm::Function::DLLExportLinkage; - + if (D->hasAttr()) return llvm::Function::WeakAnyLinkage; - + + if (D->hasAttr()) + return llvm::Function::AvailableExternallyLinkage; + // In C99 mode, 'inline' functions are guaranteed to have a strong // definition somewhere else, so we can use available_externally linkage. if (Linkage == GVA_C99Inline) @@ -634,6 +677,9 @@ if (D->hasAttr()) B.addAttribute(llvm::Attribute::MinSize); + if (D->hasAttr()) + B.addAttribute(llvm::Attribute::DLLExport); + if (LangOpts.getStackProtector() == LangOptions::SSPOn) B.addAttribute(llvm::Attribute::StackProtect); else if (LangOpts.getStackProtector() == LangOptions::SSPReq) @@ -730,7 +776,7 @@ // overridden by a definition. if (FD->hasAttr()) { - F->setLinkage(llvm::Function::DLLImportLinkage); + F->addFnAttr(llvm::Attribute::DLLImport); } else if (FD->hasAttr() || FD->isWeakImported()) { // "extern_weak" is overloaded in LLVM; we probably should have @@ -1529,7 +1575,7 @@ // Don't set internal linkage on declarations. } else { if (D->hasAttr()) - GV->setLinkage(llvm::GlobalValue::DLLImportLinkage); + GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); else if (D->hasAttr() || D->isWeakImported()) GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); @@ -1801,6 +1847,11 @@ SetCommonAttributes(D, GV); + if (D->hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); + else if (D->hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); + // Emit the initializer function if necessary. if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); @@ -1828,10 +1879,6 @@ GVALinkage Linkage = getContext().GetGVALinkageForVariable(D); if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; - else if (D->hasAttr()) - return llvm::Function::DLLImportLinkage; - else if (D->hasAttr()) - return llvm::Function::DLLExportLinkage; else if (D->hasAttr()) { // selectany symbols are externally visible, so use weak instead of // linkonce. MSVC optimizes away references to const selectany globals, so @@ -2137,17 +2184,9 @@ // Set attributes which are particular to an alias; this is a // specialization of the attributes which may be set on a global // variable/function. - if (D->hasAttr()) { - if (const FunctionDecl *FD = dyn_cast(D)) { - // The dllexport attribute is ignored for undefined symbols. - if (FD->hasBody()) - GA->setLinkage(llvm::Function::DLLExportLinkage); - } else { - GA->setLinkage(llvm::Function::DLLExportLinkage); - } - } else if (D->hasAttr() || - D->hasAttr() || - D->isWeakImported()) { + if (D->hasAttr() || + D->hasAttr() || + D->isWeakImported()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -5116,6 +5116,30 @@ isIncompleteDeclExternC(*this, NewVD)) RegisterLocallyScopedExternCDecl(NewVD, S); + if (D.isRedeclaration() && !Previous.empty()) { + VarDecl *OldVD = dyn_cast(Previous.getRepresentativeDecl()); + if (OldVD) { + const DLLImportAttr *OldImportAttr = OldVD->getAttr(); + const DLLExportAttr *OldExportAttr = OldVD->getAttr(); + const DLLImportAttr *NewImportAttr = NewVD->getAttr(); + const DLLExportAttr *NewExportAttr = NewVD->getAttr(); + + bool AddsAttr = (!OldImportAttr && NewImportAttr) || + (!OldExportAttr && NewExportAttr); + bool HasMixed = (OldImportAttr && NewExportAttr) || + (OldExportAttr && NewImportAttr); + + // NB: We don't follow MSVC here and convert a declaration to dllexport if + // a redeclaration omits dllimport. + if (AddsAttr && !HasMixed) { + Diag(NewVD->getLocation(), diag::err_attribute_dllimpexp_redeclaration) + << NewVD; + Diag(OldVD->getLocation(), diag::note_previous_declaration); + NewVD->setInvalidDecl(); + } + } + } + return NewVD; } @@ -6804,6 +6828,41 @@ } } + if (D.isRedeclaration() && !Previous.empty()) { + FunctionDecl *OldFD = dyn_cast(Previous.getRepresentativeDecl()); + if (OldFD) { + const DLLImportAttr *OldImportAttr = OldFD->getAttr(); + const DLLExportAttr *OldExportAttr = OldFD->getAttr(); + const DLLImportAttr *NewImportAttr = NewFD->getAttr(); + const DLLExportAttr *NewExportAttr = NewFD->getAttr(); + + bool AddsAttr = (!OldImportAttr && NewImportAttr) || + (!OldExportAttr && NewExportAttr); + bool HasMixed = (OldImportAttr && NewExportAttr) || + (OldExportAttr && NewImportAttr); + bool RemovesImport = OldImportAttr && + (!NewImportAttr || NewImportAttr->isInherited()); + + // NB: We don't follow MSVC here and convert a declaration to dllexport if + // a redeclaration omits dllimport. + if (!isFunctionTemplateSpecialization && AddsAttr && !HasMixed && + !OldFD->isImplicit()) { + Diag(NewFD->getLocation(), diag::err_attribute_dllimpexp_redeclaration) + << NewFD; + Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + } else if (RemovesImport && !HasMixed && !NewFD->isInlined()) { + Diag(NewFD->getLocation(), + diag::warn_redeclaration_without_attribute_prev_attribute_ignored) + << NewFD << "dllimport"; + Diag(OldFD->getLocation(), diag::note_previous_declaration); + Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); + OldFD->dropAttr(); + NewFD->dropAttr(); + } + } + } + MarkUnusedFileScopedDecl(NewFD); if (getLangOpts().CUDA) @@ -7128,6 +7187,7 @@ Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R; } } + return Redeclaration; } @@ -8298,6 +8358,26 @@ } } + if (var->isStaticDataMember() && var->isOutOfLine() && Init && + var->hasAttr()) { + + // Imported static data members cannot be defined out-of-line. + // Exception: MSVC ignores such definitions if the member is instantiated + // from a non-imported class template but the explicit instantiation is + // imported. + bool IsImportedInstantiation = false; + if (const VarDecl *MD = var->getInstantiatedFromStaticDataMember()) { + const CXXRecordDecl *RD = dyn_cast(MD->getDeclContext()); + IsImportedInstantiation = !MD->hasAttr() && RD && + RD->getTemplateSpecializationKind() == TSK_Undeclared; + } + + if (!IsImportedInstantiation) { + Diag(var->getLocation(), + diag::err_attribute_dllimport_static_field_definition); + } + } + // Require the destructor. if (const RecordType *recordType = baseType->getAs()) FinalizeVarWithDestructor(var, recordType); @@ -8323,6 +8403,25 @@ if (VD->isFileVarDecl()) MarkUnusedFileScopedDecl(VD); + const DLLImportAttr *ImportAttr = VD->getAttr(); + if (ImportAttr && !VD->isStaticDataMember()) { + // dllimport cannot be used on variable definitions. + if (VD->hasInit()) { + Diag(VD->getLocation(), diag::err_attribute_dllimport_definition); + VD->setInvalidDecl(); + return; + } + + // Check for inconsistent DLL attributes. + if (ImportAttr->isInherited()) { + Diag(VD->getLocation(), + diag::warn_redeclaration_without_attribute_prev_attribute_ignored) + << VD << "dllimport"; + Diag(ImportAttr->getLocation(), diag::note_previous_attribute); + VD->dropAttr(); + } + } + // Now we have parsed the initializer and can update the table of magic // tag values. if (!VD->hasAttr() || @@ -8950,32 +9049,17 @@ if (const FunctionProtoType *FPT = FD->getType()->getAs()) ResolveExceptionSpec(D->getLocation(), FPT); - // Checking attributes of current function definition - // dllimport attribute. - DLLImportAttr *DA = FD->getAttr(); - if (DA && (!FD->getAttr())) { - // 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) - << "dllimport"; + if (const DLLImportAttr *ImportAttr = FD->getAttr()) { + // dllimport attribute cannot be directly applied to non-inline function + // definitions. + if (!ImportAttr->isInherited() && !FD->isInlined() && + FD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) { + Diag(FD->getLocation(), diag::err_attribute_dllimport_definition); FD->setInvalidDecl(); return D; } - - // Visual C++ appears to not think this is an issue, so only issue - // a warning when Microsoft extensions are disabled. - if (!LangOpts.MicrosoftExt) { - // 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->getName() << "dllimport"; - } } + // We want to attach documentation to original Decl (which might be // a function template). ActOnDocumentableDecl(D); Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp @@ -4119,6 +4119,115 @@ } } +// Returns a DLL attribute from the declaration. +static InheritableAttr *getDLLAttrFromDecl(Decl *D) { + if (DLLImportAttr *ImpAttr = D->getAttr()) + return ImpAttr; + if (DLLExportAttr* ExpAttr = D->getAttr()) + return ExpAttr; + return NULL; +} + +static void checkRecordMemberDLLAttr(Sema &S, Decl *MemberDecl, + Attr *RecordAttr, CXXRecordDecl *RD) { + if (!MemberDecl) + return; + + InheritableAttr* MemberAttr = getDLLAttrFromDecl(MemberDecl); + bool IsRecordExported = RecordAttr && + RecordAttr->getKind() == attr::DLLExport; + bool IsMemberExported = MemberAttr && + MemberAttr->getKind() == attr::DLLExport; + + // If the class has a DLL attribute, the member cannot declare one explicitly. + if (RecordAttr && MemberAttr && !MemberAttr->isInherited()) { + S.Diag(MemberAttr->getLocation(), + diag::err_attribute_dllimpexp_member_attr_not_allowed) + << (IsRecordExported ? 1 : 0) + << (IsMemberExported ? 1 : 0); + return; + } + + // Warn if type to check is a non-exported class. + if (IsRecordExported || IsMemberExported) { + if (RD && !RD->hasAttr()) { + S.Diag(MemberDecl->getLocation(), + diag::warn_attribute_dllexport_accessible_type) + << RD->getDeclName(); + } + } + + // Let the member inherit the record attribute. + const CXXMethodDecl *MD = dyn_cast(MemberDecl); + bool Ignored = MD && MD->isDeleted(); + if (RecordAttr && !MemberAttr && !Ignored) { + InheritableAttr* NewAttr = + cast(RecordAttr->clone(S.getASTContext())); + NewAttr->setInherited(true); + MemberDecl->addAttr(NewAttr); + MemberDecl->addAttr(::new (S.getASTContext()) + UsedAttr(MemberDecl->getLocation(), S.getASTContext())); + } +} + +static void forceDefinitionOfDefaultedMembers(Sema &S, CXXRecordDecl *Class) { + for (CXXRecordDecl::method_iterator I = Class->method_begin(); + I != Class->method_end(); ++I) { + CXXMethodDecl *MD = *I; + if (MD->isDefaulted() && !(isa(MD) && MD->isTrivial())) + S.MarkFunctionReferenced(MD->getLocation(), MD); + } +} + +// Performs DLL attribute semantic checks on the declaration. +static void checkDLLAttributes(Sema &S, CXXRecordDecl *RD) { + if (!RD) + return; + + InheritableAttr* RecordAttr = getDLLAttrFromDecl(RD); + bool IsRecordExported = RecordAttr && + RecordAttr->getKind() == attr::DLLExport; + bool IsRecordImported = RecordAttr && + RecordAttr->getKind() == attr::DLLImport; + + if (IsRecordImported) + S.ForceDeclarationOfImplicitMembers(RD); + else if (IsRecordExported) { + S.ForceDeclarationOfImplicitMembers(RD); + forceDefinitionOfDefaultedMembers(S, RD); + } + + if (IsRecordExported) { + // All base classes of an exportable class must be exportable. + for (CXXRecordDecl::base_class_iterator I = RD->bases_begin(); + I != RD->bases_end(); ++I) { + CXXBaseSpecifier *BS = I; + const CXXRecordDecl *BD = BS->getType()->getAsCXXRecordDecl(); + + if (BD && !BD->hasAttr()) { + S.Diag(BS->getLocStart(), diag::warn_attribute_dllexport_base_class) + << BD->getDeclName(); + } + } + } + + // Check static data members. + for (CXXRecordDecl::static_data_iterator I = RD->static_data_begin(); + I != RD->static_data_end(); ++I) { + VarDecl *MD = *I; + CXXRecordDecl *SRD = MD->getType()->getAsCXXRecordDecl(); + checkRecordMemberDLLAttr(S, MD, RecordAttr, SRD); + } + + // Check member functions. + for (CXXRecordDecl::method_iterator I = RD->method_begin(); + I != RD->method_end(); ++I) { + CXXMethodDecl *MD = *I; + CXXRecordDecl *SRD = MD->getResultType()->getAsCXXRecordDecl(); + checkRecordMemberDLLAttr(S, MD, RecordAttr, SRD); + } +} + /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -4271,6 +4380,8 @@ // instantiated (e.g. meta-functions). This doesn't apply to classes that // have inheriting constructors. DeclareInheritingConstructors(Record); + + checkDLLAttributes(*this, Record); } /// Is the special member function which would be selected to perform the Index: cfe/trunk/lib/Sema/TargetAttributesSema.cpp =================================================================== --- cfe/trunk/lib/Sema/TargetAttributesSema.cpp +++ cfe/trunk/lib/Sema/TargetAttributesSema.cpp @@ -161,45 +161,62 @@ if (D->hasAttr()) return NULL; - if (VarDecl *VD = dyn_cast(D)) { - if (VD->hasDefinition()) { - // dllimport cannot be applied to definitions. - Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition) - << "dllimport"; - return NULL; - } - } - return ::new (Context) DLLImportAttr(Range, Context, AttrSpellingListIndex); } -static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { - // check the attribute arguments. +static bool handleDLLImportExport(Decl *D, const AttributeList &Attr, Sema &S) { + // Check the attribute arguments. if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; + return false; } - // Attribute can be applied only to functions or variables. - FunctionDecl *FD = dyn_cast(D); - if (!FD && !isa(D)) { - // Apparently Visual C++ thinks it is okay to not emit a warning - // in this case, so only emit a warning when -fms-extensions is not - // specified. - if (!S.getLangOpts().MicrosoftExt) + // Attribute can be applied only to functions, variables or tag types. For + // other types we issue a warning and drop the attribute. + if (!isa(D) && !isa(D) && !isa(D)) { + if (isa(D)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << 14 /* variables, functions and tag types */; + } else if ((!isa(D) && !isa(D)) || + !S.getLangOpts().MicrosoftExt) { + // MSVC does not warn when applied to typedefs and enums. S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; - return; + << Attr.getName() << 14 /* variables, functions and tag types */; + } + return false; } - // Currently, the dllimport attribute is ignored for inlined functions. - // Warning is emitted. - if (FD && FD->isInlineSpecified()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport"; - return; + bool IsExported = (Attr.getKind() == AttributeList::AT_DLLExport); + + // If we have a function-scope variable without explicit storage class, then + // give it external linkage. + VarDecl* VD = dyn_cast(D); + if (!IsExported && VD && VD->getLexicalDeclContext()->isFunctionOrMethod() && + VD->getStorageClass() == SC_None) { + VD->setStorageClass(SC_Extern); + } + + NamedDecl *ND = dyn_cast(D); + if (!ND) + return false; + + // Attribute cannot be applied to decls with non-external linkage. + if (!ND->isExternallyVisible()) { + bool IsExported = (Attr.getKind() == AttributeList::AT_DLLExport); + S.Diag(ND->getLocation(), diag::err_attribute_dllimpexp_not_extern_linkage) + << ND->getDeclName() << (IsExported ? 1 : 0); + ND->setInvalidDecl(); + return false; } + return true; +} + +static void handleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { + if (!handleDLLImportExport(D, Attr, S)) + return; + unsigned Index = Attr.getAttributeSpellingListIndex(); DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index); if (NewAttr) @@ -220,33 +237,16 @@ AttrSpellingListIndex); } -static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { - // check the attribute arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // Attribute can be applied only to functions or variables. - FunctionDecl *FD = dyn_cast(D); - if (!FD && !isa(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; +static void handleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) { + if (!handleDLLImportExport(D, Attr, S)) return; - } - - // Currently, the dllexport attribute is ignored for inlined functions, unless - // the -fkeep-inline-functions flag has been used. Warning is emitted; - if (FD && FD->isInlineSpecified()) { - // FIXME: ... unless the -fkeep-inline-functions flag has been used. - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport"; - return; - } unsigned Index = Attr.getAttributeSpellingListIndex(); DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index); - if (NewAttr) + if (NewAttr) { D->addAttr(NewAttr); + D->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); + } } namespace { @@ -259,9 +259,9 @@ if (Triple.getOS() == llvm::Triple::Win32 || Triple.getOS() == llvm::Triple::MinGW32) { switch (Attr.getKind()) { - case AttributeList::AT_DLLImport: HandleDLLImportAttr(D, Attr, S); + case AttributeList::AT_DLLImport: handleDLLImportAttr(D, Attr, S); return true; - case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S); + case AttributeList::AT_DLLExport: handleDLLExportAttr(D, Attr, S); return true; default: break; } Index: cfe/trunk/test/CodeGen/dllimport-dllexport.c =================================================================== --- cfe/trunk/test/CodeGen/dllimport-dllexport.c +++ cfe/trunk/test/CodeGen/dllimport-dllexport.c @@ -1,12 +1,55 @@ -// RUN: %clang_cc1 -triple i386-mingw32 -emit-llvm < %s | FileCheck %s - -void __attribute__((dllimport)) foo1(); -void __attribute__((dllexport)) foo1(){} -// CHECK: define dllexport void @foo1 -void __attribute__((dllexport)) foo2(); - -// PR6269 -__declspec(dllimport) void foo3(); -__declspec(dllexport) void foo3(){} -// CHECK: define dllexport void @foo3 -__declspec(dllexport) void foo4(); +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple i386-mingw32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-mingw32 -emit-llvm %s -o - | FileCheck %s + +// Global vars + +// Export definitions. +// CHECK: @ExportedGlobalInit = global i32 1, align 4, dllexport +__declspec(dllexport) int ExportedGlobalInit = 1; + +// Force declaration, then export when defined. +// CHECK: @ExportedGlobalDeclInit = global i32 2, align 4, dllexport +__declspec(dllexport) extern int ExportedGlobalDeclInit; +int ExportedGlobalDeclInit = 2; + +// Export definitions without initializer. +// CHECK: @ExportedGlobalDef = common global i32 0, align 4, dllexport +__declspec(dllexport) int ExportedGlobalDef; + +// Declarations are not exported. +// CHECK-NOT: @GlobalDecl +__declspec(dllexport) extern int GlobalDecl; + +// dllexport has precedence over dllimport +// CHECK: @PrecedenceGlobal = common global i32 0, align 4, dllexport +__declspec(dllimport) int PrecedenceGlobal; +__declspec(dllexport) int PrecedenceGlobal; + + +// Functions + +// Export function. +// CHECK: define void @exported() #[[ExportGrp:[0-9]+]] +// CHECK: define void @externExported() #[[ExportGrp]] +__declspec(dllexport) void exported() {} + +__declspec(dllexport) extern void externExported() {} + + +// Export ignored for declarations. +// CHECK-NOT: define {{.*}}void @ignoredDecl() +__declspec(dllexport) void ignoredDecl(); + + +// dllexport has precedence over dllimport +// CHECK: define void @precedence() #[[ExportGrp]] +__declspec(dllimport) void precedence(); +__declspec(dllexport) void precedence() {} + + +__declspec(dllimport) void impNormal(); + + +// CHECK: attributes #[[ExportGrp]] = { dllexport{{.*}} } Index: cfe/trunk/test/CodeGenCXX/dllexport-functions.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllexport-functions.cpp @@ -0,0 +1,97 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm %s -o - | FileCheck %s + +// Helper structs to make templates more expressive. +struct ImplicitInst_Exported {}; +struct ImplicitInst_NotExported {}; +struct ExplicitInst_Exported {}; +struct ExplicitInst_NotExported {}; +struct ExplicitSpec_Exported {}; +struct ExplicitSpec_NotExported {}; +struct ExplicitSpec_Inline_Exported {}; + + +// Export function. +// CHECK: define void @_Z8exportedv() #[[ExportGrp:[0-9]+]] +// CHECK: define void @_Z14externExportedv() #[[ExportGrp]] +// CHECK: define void @externCExported() #[[ExportGrp]] +__declspec(dllexport) void exported() {} +__declspec(dllexport) extern void externExported() {} +extern "C" __declspec(dllexport) void externCExported() {} + + +// Export explicit inline functions. +// CHECK: define linkonce_odr void @_Z14inlineExportedv() #[[InlineExportGrp:[0-9]+]] +// CHECK: define linkonce_odr void @_Z20externInlineExportedv() #[[InlineExportGrp]] +// CHECK: define linkonce_odr void @externCInlineExported() #[[InlineExportGrp]] +__declspec(dllexport) inline void inlineExported() {} +__declspec(dllexport) extern inline void externInlineExported() {} +extern "C" __declspec(dllexport) inline void externCInlineExported() {} + + +// Export ignored for declarations. +// CHECK-NOT: define {{.*}}void @_Z10ignoredDeclv() +__declspec(dllexport) void ignoredDecl(); + + +// dllexport has precedence over dllimport +// CHECK: define void @_Z10precedencev() #[[ExportGrp]] +__declspec(dllimport) void precedence(); +__declspec(dllexport) void precedence() {} + + +// Exported function template. +// CHECK: define void @_Z12exportedTmplI21ExplicitSpec_ExportedEvv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_Z12exportedTmplI28ExplicitSpec_Inline_ExportedEvv() #[[InlineExportGrp]] +// CHECK: define void @_Z12exportedTmplI24ExplicitSpec_NotExportedEvv() #[[NotExportGrp:[0-9]+]] +// CHECK: define weak_odr void @_Z12exportedTmplI21ExplicitInst_ExportedEvv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_Z12exportedTmplI21ImplicitInst_ExportedEvv() #[[ExportGrp]] +template __declspec(dllexport) void exportedTmpl() {} + +// Exporting specialization of an exported function template. +template<> __declspec(dllexport) void exportedTmpl() {} + +// Exporting specialization with explicit inline. +template<> __declspec(dllexport) inline void exportedTmpl() {} + +// Not exporting template specializations of an exported function template. +template<> void exportedTmpl() {} + +// Instantiate +template void exportedTmpl(); + +void dummy() { + // Export implicit instantiation. + exportedTmpl(); +} + + +// Non-exported function template. +// CHECK: define void @_Z15notExportedTmplI21ExplicitSpec_ExportedEvv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_Z15notExportedTmplI28ExplicitSpec_Inline_ExportedEvv() #[[InlineExportGrp]] +// CHECK: define weak_odr void @_Z15notExportedTmplI21ExplicitInst_ExportedEvv() #[[ExportGrp]] +// CHECK: define weak_odr void @_Z15notExportedTmplI24ExplicitInst_NotExportedEvv() #[[NotExportGrp]] +// CHECK: define linkonce_odr void @_Z15notExportedTmplI24ImplicitInst_NotExportedEvv() #[[NotExportGrp]] +template void notExportedTmpl() {} + +// Exporting specialization of a non-exported function template. +template<> __declspec(dllexport) void notExportedTmpl() {} + +// Exporting specialization with explicit inline. +template<> __declspec(dllexport) inline void notExportedTmpl() {} + +// Explicitly export explicit instantiation. +template __declspec(dllexport) void notExportedTmpl(); + +// Not exporting explicit instantiation. +template void notExportedTmpl(); + +void dummy2() { + // Not exporting implicit instantiation. + notExportedTmpl(); +} + + +// CHECK: attributes #[[ExportGrp]] = { dllexport{{.*}} } +// CHECK: attributes #[[InlineExportGrp]] = { dllexport inlinehint{{.*}} } +// CHECK: attributes #[[NotExportGrp]] = { nounwind{{.*}} } Index: cfe/trunk/test/CodeGenCXX/dllexport-globals.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllexport-globals.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm %s -o - | FileCheck %s + +// Export definitions. +// CHECK: @ExportedGlobalInit = global i32 1, align 4, dllexport +__declspec(dllexport) int ExportedGlobalInit = 1; + +// Export definitions without initializer. +// CHECK: @ExportedGlobalDef = global i32 0, align 4, dllexport +__declspec(dllexport) int ExportedGlobalDef; + +// Force declaration, then export when defined. +// CHECK: @ExportedGlobalDeclInit = global i32 2, align 4, dllexport +__declspec(dllexport) extern int ExportedGlobalDeclInit; +int ExportedGlobalDeclInit = 2; + +// Declarations are not exported. +// CHECK-NOT: @GlobalDecl +__declspec(dllexport) extern int GlobalDecl; + +// dllexport has precedence over dllimport +// CHECK: @PrecedenceGlobal = global i32 0, align 4, dllexport +__declspec(dllimport) int PrecedenceGlobal; +__declspec(dllexport) int PrecedenceGlobal; Index: cfe/trunk/test/CodeGenCXX/dllexport-members.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllexport-members.cpp @@ -0,0 +1,125 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm %s -o - | FileCheck %s + +// CHECK: @_ZN1A11staticFieldE = global i32 1, align 4, dllexport +// CHECK: @_ZN1A20protectedStaticFieldE = global i32 1, align 4, dllexport +// CHECK: @_ZN1A18privateStaticFieldE = global i32 1, align 4, dllexport + +// CHECK: define linkonce_odr void @_ZN1A14implicitInlineEv(%struct.A* %this) #[[ExportGrp:[0-9]+]] +// CHECK: define linkonce_odr void @_ZN1A21virtualImplicitInlineEv(%struct.A* %this) unnamed_addr #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A20staticImplicitInlineEv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A23protectedImplicitInlineEv(%struct.A* %this) #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A30protectedVirtualImplicitInlineEv(%struct.A* %this) unnamed_addr #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A29protectedStaticImplicitInlineEv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A21privateImplicitInlineEv(%struct.A* %this) #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A28privateVirtualImplicitInlineEv(%struct.A* %this) unnamed_addr #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A27privateStaticImplicitInlineEv() #[[ExportGrp]] + +// CHECK: define void @_ZN1A13ignoredNormalEv(%struct.A* %this) #[[NotExportGrp:[0-9]+]] +// CHECK: define void @_ZN1A21ignoredExplicitInlineEv(%struct.A* %this) #[[NotExportGrp]] +// CHECK: define void @_ZN1A14ignoredVirtualEv(%struct.A* %this) unnamed_addr #[[NotExportGrp]] +// CHECK: define void @_ZN1A28ignoredVirtualExplicitInlineEv(%struct.A* %this) unnamed_addr #[[NotExportGrp]] +// CHECK: define void @_ZN1A13ignoredStaticEv() #[[NotExportGrp]] +// CHECK: define void @_ZN1A27ignoredStaticExplicitInlineEv() #[[NotExportGrp]] + +// CHECK: define void @_ZN1A9normalFunEv(%struct.A* %this) #[[ExportGrp]] +// CHECK: define void @_ZN1A10virtualFunEv(%struct.A* %this) unnamed_addr #[[ExportGrp]] +// CHECK: define void @_ZN1A9staticFunEv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A14explicitInlineEv(%struct.A* %this) #[[InlineExportGrp:[0-9]+]] +// CHECK: define linkonce_odr void @_ZN1A21virtualExplicitInlineEv(%struct.A* %this) unnamed_addr #[[InlineExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A20staticExplicitInlineEv() #[[InlineExportGrp]] +// CHECK: define void @_ZN1A18protectedNormalFunEv(%struct.A* %this) #[[ExportGrp]] +// CHECK: define void @_ZN1A19protectedVirtualFunEv(%struct.A* %this) unnamed_addr #[[ExportGrp]] +// CHECK: define void @_ZN1A18protectedStaticFunEv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A23protectedExplicitInlineEv(%struct.A* %this) #[[InlineExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A30protectedVirtualExplicitInlineEv(%struct.A* %this) unnamed_addr #[[InlineExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A29protectedStaticExplicitInlineEv() #[[InlineExportGrp]] +// CHECK: define void @_ZN1A16privateNormalFunEv(%struct.A* %this) #[[ExportGrp]] +// CHECK: define void @_ZN1A17privateVirtualFunEv(%struct.A* %this) unnamed_addr #[[ExportGrp]] +// CHECK: define void @_ZN1A16privateStaticFunEv() #[[ExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A21privateExplicitInlineEv(%struct.A* %this) #[[InlineExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A28privateVirtualExplicitInlineEv(%struct.A* %this) unnamed_addr #[[InlineExportGrp]] +// CHECK: define linkonce_odr void @_ZN1A27privateStaticExplicitInlineEv() #[[InlineExportGrp]] + +// CHECK: attributes #[[ExportGrp]] = { dllexport{{.*}} } +// CHECK: attributes #[[NotExportGrp]] = { nounwind{{.*}} } +// CHECK: attributes #[[InlineExportGrp]] = { dllexport inlinehint{{.*}} } + + +struct A { + void ignoredNormal(); + void ignoredImplicitInline() {} + void ignoredExplicitInline(); + virtual void ignoredVirtual(); + virtual void ignoredVirtualImplicitInline() {} + virtual void ignoredVirtualExplicitInline(); + static void ignoredStatic(); + static void ignoredStaticImplicitInline() {} + static void ignoredStaticExplicitInline(); + static int ignoredStaticField; + int ignoredField; + + __declspec(dllexport) void normalFun(); + __declspec(dllexport) void implicitInline() {} + __declspec(dllexport) void explicitInline(); + __declspec(dllexport) virtual void virtualFun(); + __declspec(dllexport) virtual void virtualImplicitInline() {} + __declspec(dllexport) virtual void virtualExplicitInline(); + __declspec(dllexport) static void staticFun(); + __declspec(dllexport) static void staticImplicitInline() {} + __declspec(dllexport) static void staticExplicitInline(); + __declspec(dllexport) static int staticField; + int field; +protected: + __declspec(dllexport) void protectedNormalFun(); + __declspec(dllexport) void protectedImplicitInline() {} + __declspec(dllexport) void protectedExplicitInline(); + __declspec(dllexport) virtual void protectedVirtualFun(); + __declspec(dllexport) virtual void protectedVirtualImplicitInline() {} + __declspec(dllexport) virtual void protectedVirtualExplicitInline(); + __declspec(dllexport) static void protectedStaticFun(); + __declspec(dllexport) static void protectedStaticImplicitInline() {} + __declspec(dllexport) static void protectedStaticExplicitInline(); + __declspec(dllexport) static int protectedStaticField; + int protectedField; +private: + __declspec(dllexport) void privateNormalFun(); + __declspec(dllexport) void privateImplicitInline() {} + __declspec(dllexport) void privateExplicitInline(); + __declspec(dllexport) virtual void privateVirtualFun(); + __declspec(dllexport) virtual void privateVirtualImplicitInline() {} + __declspec(dllexport) virtual void privateVirtualExplicitInline(); + __declspec(dllexport) static void privateStaticFun(); + __declspec(dllexport) static void privateStaticImplicitInline() {} + __declspec(dllexport) static void privateStaticExplicitInline(); + __declspec(dllexport) static int privateStaticField; + int privateField; +}; +void A::ignoredNormal() {} +void A::ignoredExplicitInline() {} +void A::ignoredVirtual() {} +void A::ignoredVirtualExplicitInline() {} +void A::ignoredStatic() {} +void A::ignoredStaticExplicitInline() {} +int A::ignoredStaticField = 1; +void A::normalFun() {} +void A::virtualFun() {} +void A::staticFun() {} +inline void A::explicitInline() {} +inline void A::virtualExplicitInline() {} +inline void A::staticExplicitInline() {} +int A::staticField = 1; +void A::protectedNormalFun() {} +void A::protectedVirtualFun() {} +void A::protectedStaticFun() {} +inline void A::protectedExplicitInline() {} +inline void A::protectedVirtualExplicitInline() {} +inline void A::protectedStaticExplicitInline() {} +int A::protectedStaticField = 1; +void A::privateNormalFun() {} +void A::privateVirtualFun() {} +void A::privateStaticFun() {} +inline void A::privateExplicitInline() {} +inline void A::privateVirtualExplicitInline() {} +inline void A::privateStaticExplicitInline() {} +int A::privateStaticField = 1; Index: cfe/trunk/test/CodeGenCXX/dllexport-records.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllexport-records.cpp @@ -0,0 +1,311 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -emit-llvm %s -o - -O0 | FileCheck --check-prefix=NOP %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -std=c++11 -emit-llvm %s -o - -O0 | FileCheck --check-prefix=NOP %s + + +// Export non-dynamic class. +// +// NOP-DAG: @_ZN1A17publicStaticFieldE = global i32 1, align 4, dllexport +// NOP-DAG: @_ZN1A20protectedStaticFieldE = global i32 1, align 4, dllexport +// NOP-DAG: @_ZN1A18privateStaticFieldE = global i32 1, align 4, dllexport +// NOP-DAG: define void @_ZN1A12publicNormalEv({{[^\)]*}}) #[[ExportGrp:[0-9]+]] +// NOP-DAG: define linkonce_odr void @_ZN1A18publicNormalInsideEv({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN1A21publicNormalInlineDefEv({{[^\)]*}}) #[[InlineExportGrp:[0-9]+]] +// NOP-DAG: define linkonce_odr void @_ZN1A22publicNormalInlineDeclEv({{[^\)]*}}) #[[InlineExportGrp]] +// NOP-DAG: define void @_ZN1A12publicStaticEv() #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN1A18publicStaticInsideEv() #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN1A21publicStaticInlineDefEv() #[[InlineExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN1A22publicStaticInlineDeclEv() #[[InlineExportGrp]] +// NOP-DAG: define void @_ZN1A15protectedNormalEv({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define void @_ZN1A15protectedStaticEv() #[[ExportGrp]] +// NOP-DAG: define void @_ZN1A13privateNormalEv({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define void @_ZN1A13privateStaticEv() #[[ExportGrp]] +struct __declspec(dllexport) A { +public: + void publicNormal(); + void publicNormalInside() {} + void publicNormalInlineDef(); + inline void publicNormalInlineDecl(); + static void publicStatic(); + static void publicStaticInside() {} + static void publicStaticInlineDef(); + static inline void publicStaticInlineDecl(); + + int publicField; + static int publicStaticField; + static const int publicStaticConstField; + static const int publicStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int publicConstexprField = 2; +#endif + +protected: + void protectedNormal(); + static void protectedStatic(); + + int protectedField; + static int protectedStaticField; + static const int protectedStaticConstField; + static const int protectedStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int protectedConstexprField = 2; +#endif + +private: + void privateNormal(); + static void privateStatic(); + + int privateField; + static int privateStaticField; + static const int privateStaticConstField; + static const int privateStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int privateConstexprField = 2; +#endif +}; + void A::publicNormal() {} +inline void A::publicNormalInlineDef() {} + void A::publicNormalInlineDecl() {} + void A::publicStatic() {} +inline void A::publicStaticInlineDef() {} + void A::publicStaticInlineDecl() {} + int A::publicStaticField = 1; + const int A::publicStaticConstField = 1; + + void A::protectedNormal() {} + void A::protectedStatic() {} + int A::protectedStaticField = 1; + const int A::protectedStaticConstField = 1; + + void A::privateNormal() {} + void A::privateStatic() {} + int A::privateStaticField = 1; + const int A::privateStaticConstField = 1; + + +struct X {}; +void* malloc(__SIZE_TYPE__ size); +void free(void* p); + + +// Export special members. +// +// NOP-DAG: define void @_ZN7SpecialC1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialC2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialC1ERKS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialC2ERKS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialC1EOS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialC2EOS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialC1E1X({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialC2E1X({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define {{[^ ]*}} @_ZN7SpecialaSERKS_({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define {{[^ ]*}} @_ZN7SpecialaSEOS_({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define {{[^ ]*}} @_ZN7SpecialaSE1X({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define i8 @_ZN7Specialcv1XEv({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialD1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialD2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define i8* @_ZN7SpecialnwE{{[jy)]}}({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define i8* @_ZN7SpecialnaE{{[jy)]}}({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialdlEPv({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define void @_ZN7SpecialdaEPv({{[^\)]*}}) #[[ExportGrp]] +struct __declspec(dllexport) Special { + Special(); + Special(const Special&); + Special(Special&&); + Special(X); + Special& operator=(const Special&); + Special& operator=(Special&&); + Special& operator=(X); + operator X(); + ~Special(); + void* operator new(__SIZE_TYPE__); + void* operator new[](__SIZE_TYPE__); + void operator delete(void*); + void operator delete[](void*); +}; +Special::Special() {} +Special::Special(const Special&) {} +Special::Special(Special&&) {} +Special::Special(X) {} +Special& Special::operator=(const Special&) { return *this; } +Special& Special::operator=(Special&&) { return *this; } +Special& Special::operator=(X) { return *this; } +Special::operator X() { return X(); } +Special::~Special() {} +void* Special::operator new(__SIZE_TYPE__ n) { return malloc(n); } +void* Special::operator new[](__SIZE_TYPE__ n) { return malloc(n); } +void Special::operator delete(void* p) { free(p); } +void Special::operator delete[](void* p) { free(p); } + + +// Export inline special members. +// +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC1ERKS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC2ERKS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC1EOS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC2EOS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC1E1X({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineC2E1X({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr {{[^ ]*}} @_ZN13SpecialInlineaSERKS_({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr {{[^ ]*}} @_ZN13SpecialInlineaSEOS_({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr {{[^ ]*}} @_ZN13SpecialInlineaSE1X({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr i8 @_ZN13SpecialInlinecv1XEv({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineD1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlineD2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr i8* @_ZN13SpecialInlinenwE{{[jy)]}}({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr i8* @_ZN13SpecialInlinenaE{{[jy)]}}({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlinedlEPv({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13SpecialInlinedaEPv({{[^\)]*}}) #[[ExportGrp]] +struct __declspec(dllexport) SpecialInline { + SpecialInline() {} + SpecialInline(const SpecialInline&) {} + SpecialInline(SpecialInline&&) {} + SpecialInline(X) {} + SpecialInline& operator=(const SpecialInline&) { return *this; } + SpecialInline& operator=(SpecialInline&&) { return *this; } + SpecialInline& operator=(X) { return *this; } + operator X() { return X(); } + ~SpecialInline() {} + void* operator new(__SIZE_TYPE__ n) { return malloc(n); } + void* operator new[](__SIZE_TYPE__ n) { return malloc(n); } + void operator delete(void* p) { free(p); } + void operator delete[](void* p) { free(p); } +}; + + +// Export defaulted special members. +// +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedC1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedC2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedC1ERKS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedC2ERKS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr {{[^ ]*}} @_ZN9DefaultedaSERKS_({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedC1EOS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedC2EOS_({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr {{[^ ]*}} @_ZN9DefaultedaSEOS_({{[^\)]*}}) #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedD1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN9DefaultedD2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +struct __declspec(dllexport) Defaulted { + Defaulted() = default; + Defaulted(const Defaulted&) = default; + Defaulted& operator=(const Defaulted&) = default; + Defaulted(Defaulted&&) = default; + Defaulted& operator=(Defaulted&&) = default; + ~Defaulted() = default; + Defaulted(X); + Defaulted& operator=(X); + operator X(); + Special v; // ensure non-trivial members +}; + + +// NOP-DAG: define linkonce_odr void @_ZN7Attribs12AlwaysInlineEv({{[^\)]*}}) #[[AlwaysInlineExportGrp:[0-9]+]] +// NOP-DAG: define linkonce_odr void @_ZN7Attribs11NeverInlineEv({{[^\)]*}}) #[[NoInlineExportGrp:[0-9]+]] +struct __declspec(dllexport) Attribs { + __attribute__((always_inline)) void AlwaysInline() {} + __attribute__((noinline)) void NeverInline() {} +}; + + +// Export dynamic class with key function. +// +// NOP-DAG: @_ZTV7Virtual = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTI7Virtual = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTS7Virtual = constant {{.*}}, dllexport +// NOP-DAG: define void @_ZN7Virtual13publicVirtualEv({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN7Virtual19publicVirtualInsideEv({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN7Virtual22publicVirtualInlineDefEv({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN7Virtual23publicVirtualInlineDeclEv({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +struct __declspec(dllexport) Virtual { + virtual ~Virtual(); + virtual void publicVirtual(); + virtual void publicVirtualInside() {} + virtual void publicVirtualInlineDef(); + virtual inline void publicVirtualInlineDecl(); +}; + Virtual::~Virtual() {} + void Virtual::publicVirtual() {} +inline void Virtual::publicVirtualInlineDef() {} + void Virtual::publicVirtualInlineDecl() {} + + +// Export dynamic class without key function. +// +// Note: vtable and rtti are not exported. +// NOP-DAG: @_ZTV13VirtualInline = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: @_ZTT13VirtualInline = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: @_ZTI13VirtualInline = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// NOP-DAG: @_ZTS13VirtualInline = linkonce_odr constant {{.*}}"{{$}} +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInlineC1Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInlineC2Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInlineC1ERKS_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInlineC2ERKS_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// NOP-DAG: define linkonce_odr {{[^ ]*}} @_ZN13VirtualInlineaSERKS_({{[^\)]*}}) #[[InlineExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInlineD0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInlineD1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInlineD2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZN13VirtualInline19publicVirtualInsideEv({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +struct __declspec(dllexport) VirtualInline : virtual X { + virtual ~VirtualInline() {} + virtual void publicVirtualInside() {} +}; + + +// Export dynamic class with virtual inheritance. +// +// NOP-DAG: @_ZTV12VirtualBase1 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTI12VirtualBase1 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTS12VirtualBase1 = constant {{.*}}, dllexport +// +// NOP-DAG: @_ZTV12VirtualBase2 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTT12VirtualBase2 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTI12VirtualBase2 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTS12VirtualBase2 = constant {{.*}}, dllexport +// NOP-DAG: define void @_ZTv0_n{{12|24}}_N12VirtualBase2D0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZTv0_n{{12|24}}_N12VirtualBase2D1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] + +// NOP-DAG: @_ZTV12VirtualBase3 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTT12VirtualBase3 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTI12VirtualBase3 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: @_ZTS12VirtualBase3 = constant {{.*}}, dllexport +// NOP-DAG: @_ZTC12VirtualBase30_12VirtualBase2 = unnamed_addr constant {{.*}}, dllexport +// NOP-DAG: define void @_ZTv0_n{{12|24}}_N12VirtualBase3D0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define void @_ZTv0_n{{12|24}}_N12VirtualBase3D1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +struct __declspec(dllexport) VirtualBase1 { virtual ~VirtualBase1(); }; +struct __declspec(dllexport) VirtualBase2 : virtual VirtualBase1 { virtual ~VirtualBase2(); }; +struct __declspec(dllexport) VirtualBase3 : virtual VirtualBase2 { virtual ~VirtualBase3(); }; +VirtualBase1::~VirtualBase1() {} +VirtualBase2::~VirtualBase2() {} +VirtualBase3::~VirtualBase3() {} + + +// Export dynamic class without key function and with virtual inheritance. +// +// NOP-DAG: @_ZTV18VirtualInlineBase1 = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: @_ZTI18VirtualInlineBase1 = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// NOP-DAG: @_ZTS18VirtualInlineBase1 = linkonce_odr constant {{.*}}"{{$}} +// +// NOP-DAG: @_ZTV18VirtualInlineBase2 = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: @_ZTT18VirtualInlineBase2 = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: @_ZTI18VirtualInlineBase2 = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// NOP-DAG: @_ZTS18VirtualInlineBase2 = linkonce_odr constant {{.*}}"{{$}} +// NOP-DAG: define linkonce_odr void @_ZTv0_n{{12|24}}_N18VirtualInlineBase2D0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZTv0_n{{12|24}}_N18VirtualInlineBase2D1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// +// NOP-DAG: @_ZTV18VirtualInlineBase3 = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: @_ZTT18VirtualInlineBase3 = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: @_ZTI18VirtualInlineBase3 = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// NOP-DAG: @_ZTS18VirtualInlineBase3 = linkonce_odr constant {{.*}}"{{$}} +// NOP-DAG: @_ZTC18VirtualInlineBase30_18VirtualInlineBase2 = linkonce_odr unnamed_addr constant {{.*}}]{{$}} +// NOP-DAG: define linkonce_odr void @_ZTv0_n{{12|24}}_N18VirtualInlineBase3D0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// NOP-DAG: define linkonce_odr void @_ZTv0_n{{12|24}}_N18VirtualInlineBase3D1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +struct __declspec(dllexport) VirtualInlineBase1 { virtual ~VirtualInlineBase1() {} }; +struct __declspec(dllexport) VirtualInlineBase2 : virtual VirtualInlineBase1 { virtual ~VirtualInlineBase2() {} }; +struct __declspec(dllexport) VirtualInlineBase3 : virtual VirtualInlineBase2 { virtual ~VirtualInlineBase3() {} }; + + +// NOP: attributes #[[ExportGrp]] = { dllexport nounwind {{["\}]}} +// NOP: attributes #[[InlineExportGrp]] = { dllexport inlinehint nounwind {{["\}]}} +// NOP: attributes #[[AlwaysInlineExportGrp]] = { alwaysinline dllexport nounwind {{["\}]}} +// NOP: attributes #[[NoInlineExportGrp]] = { dllexport noinline nounwind {{["\}]}} Index: cfe/trunk/test/CodeGenCXX/dllexport-templates.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllexport-templates.cpp @@ -0,0 +1,327 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -std=c++11 -emit-llvm %s -o - | FileCheck %s + +// Helper structs to make template specializations more expressive. +struct ExplicitInst_Exported {}; +struct ExplicitInst_ExplicitExported {}; +struct ExplicitSpec_Exported {}; +struct ExplicitSpec_NotExported {}; + + +// Exported class template. +template +struct __declspec(dllexport) Exp { + void normalDefined(); + void normalInside() {} + void normalInlineDef(); + inline void normalInlineDecl(); + static void staticDefined(); + static void staticInside() {} + static void staticInlineDef(); + static inline void staticInlineDecl(); + static int staticField; +}; +template void Exp::normalDefined() {} +template inline void Exp::normalInlineDef() {} +template void Exp::normalInlineDecl() {} +template void Exp::staticDefined() {} +template inline void Exp::staticInlineDef() {} +template void Exp::staticInlineDecl() {} +template int Exp::staticField = 1; + + +// Export explicit instantiation of an exported class template. +// +// CHECK-DAG: @_ZN3ExpI21ExplicitInst_ExportedE11staticFieldE = weak_odr global i32 1, align 4, dllexport +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE13normalDefinedEv({{[^\)]*}}) #[[ExportGrp:[0-9]+]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE12normalInsideEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE15normalInlineDefEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE16normalInlineDeclEv({{[^\)]*}}) #[[InlineExportGrp:[0-9]+]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE13staticDefinedEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE12staticInsideEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE15staticInlineDefEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI21ExplicitInst_ExportedE16staticInlineDeclEv() #[[InlineExportGrp]] +template struct Exp; + + +// Explicitly export explicit instantiation of an exported class template. +// +// CHECK-DAG: @_ZN3ExpI29ExplicitInst_ExplicitExportedE11staticFieldE = weak_odr global i32 1, align 4, dllexport +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE13normalDefinedEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE12normalInsideEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE15normalInlineDefEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE16normalInlineDeclEv({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE13staticDefinedEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE12staticInsideEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE15staticInlineDefEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN3ExpI29ExplicitInst_ExplicitExportedE16staticInlineDeclEv() #[[InlineExportGrp]] +template struct __declspec(dllexport) Exp; + + +// Export a specialization of a class template. +// +// CHECK-DAG: @_ZN3ExpI21ExplicitSpec_ExportedE11staticFieldE = global i32 1, align 4, dllexport +// CHECK-DAG: define void @_ZN3ExpI21ExplicitSpec_ExportedE13normalDefinedEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN3ExpI21ExplicitSpec_ExportedE12normalInsideEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN3ExpI21ExplicitSpec_ExportedE15normalInlineDefEv({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN3ExpI21ExplicitSpec_ExportedE16normalInlineDeclEv({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: define void @_ZN3ExpI21ExplicitSpec_ExportedE13staticDefinedEv() #[[ExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN3ExpI21ExplicitSpec_ExportedE12staticInsideEv() #[[ExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN3ExpI21ExplicitSpec_ExportedE15staticInlineDefEv() #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN3ExpI21ExplicitSpec_ExportedE16staticInlineDeclEv() #[[InlineExportGrp]] +template<> +struct __declspec(dllexport) Exp { + void normalDefined(); + void normalDecl(); + void normalInside() {} + void normalInlineDef(); + inline void normalInlineDecl(); + static void staticDefined(); + static void staticDecl(); + static void staticInside() {} + static void staticInlineDef(); + static inline void staticInlineDecl(); + static int staticField; +}; + void Exp::normalDefined() {} +inline void Exp::normalInlineDef() {} + void Exp::normalInlineDecl() {} + void Exp::staticDefined() {} +inline void Exp::staticInlineDef() {} + void Exp::staticInlineDecl() {} + int Exp::staticField = 1; + + +// Not exporting specialization of an exported class template. +// CHECK-DAG: define void @_ZN3ExpI24ExplicitSpec_NotExportedE13normalDefinedEv({{[^\)]*}}) #[[NotExportGrp:[0-9]+]] +template<> +struct Exp { + void normalDefined(); +}; +void Exp::normalDefined() {} + + +// Non-exported class template. +template +struct NotExp { + void normalDefined(); + void normalDecl(); + void normalInside() {} + void normalInlineDef(); + inline void normalInlineDecl(); + static void staticDefined(); + static void staticDecl(); + static void staticInside() {} + static void staticInlineDef(); + static inline void staticInlineDecl(); + static int staticField; +}; +template void NotExp::normalDefined() {} +template inline void NotExp::normalInlineDef() {} +template void NotExp::normalInlineDecl() {} +template void NotExp::staticDefined() {} +template inline void NotExp::staticInlineDef() {} +template void NotExp::staticInlineDecl() {} +template int NotExp::staticField = 1; + + +// Explicitly export explicit instantiation of a non-exported class template. +// +// CHECK-DAG: @_ZN6NotExpI21ExplicitInst_ExportedE11staticFieldE = weak_odr global i32 1, align 4, dllexport +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE13normalDefinedEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE12normalInsideEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE15normalInlineDefEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE16normalInlineDeclEv({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE13staticDefinedEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE12staticInsideEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE15staticInlineDefEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6NotExpI21ExplicitInst_ExportedE16staticInlineDeclEv() #[[InlineExportGrp]] +template struct __declspec(dllexport) NotExp; + + +// Non-exported class template with exported members. +template +struct ExpMem { + __declspec(dllexport) void normalDefined(); + __declspec(dllexport) void normalInside() {} + __declspec(dllexport) void normalInlineDef(); + __declspec(dllexport) inline void normalInlineDecl(); + __declspec(dllexport) static void staticDefined(); + __declspec(dllexport) static void staticInside() {} + __declspec(dllexport) static void staticInlineDef(); + __declspec(dllexport) static inline void staticInlineDecl(); + __declspec(dllexport) static int staticField; + void ignoredNormal(); +}; +template void ExpMem::normalDefined() {} +template inline void ExpMem::normalInlineDef() {} +template void ExpMem::normalInlineDecl() {} +template void ExpMem::staticDefined() {} +template inline void ExpMem::staticInlineDef() {} +template void ExpMem::staticInlineDecl() {} +template void ExpMem::ignoredNormal() {} +template int ExpMem::staticField = 1; + + +// Export selected members of explicit instantiation of non-exported class template. +// +// CHECK-DAG: @_ZN6ExpMemI21ExplicitInst_ExportedE11staticFieldE = weak_odr global i32 1, align 4, dllexport +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE13normalDefinedEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE12normalInsideEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE15normalInlineDefEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE16normalInlineDeclEv({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE13staticDefinedEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE12staticInsideEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE15staticInlineDefEv() #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE16staticInlineDeclEv() #[[InlineExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ExpMemI21ExplicitInst_ExportedE13ignoredNormalEv({{[^\)]*}}) #[[NotExportGrp]] +template struct ExpMem; + + +// Export dynamic class template. +// +// CHECK-DAG: @_ZTV7VirtualI21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTS7VirtualI21ExplicitInst_ExportedE = weak_odr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTI7VirtualI21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: define linkonce_odr void @_ZN7VirtualI21ExplicitInst_ExportedEC1Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN7VirtualI21ExplicitInst_ExportedEC2Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN7VirtualI21ExplicitInst_ExportedEC1ERKS1_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN7VirtualI21ExplicitInst_ExportedEC2ERKS1_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr {{[^ ]*}} @_ZN7VirtualI21ExplicitInst_ExportedEaSERKS1_({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: declare void @_ZN7VirtualI21ExplicitInst_ExportedED0Ev({{[^\)]*}}) #[[NotExportGrp]] +// CHECK-DAG: declare void @_ZN7VirtualI21ExplicitInst_ExportedED1Ev({{[^\)]*}}) #[[NotExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN7VirtualI21ExplicitInst_ExportedE14virtualDefinedEv({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN7VirtualI21ExplicitInst_ExportedE13virtualInsideEv({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN7VirtualI21ExplicitInst_ExportedE16virtualInlineDefEv({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN7VirtualI21ExplicitInst_ExportedE17virtualInlineDeclEv({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +template +struct __declspec(dllexport) Virtual +{ + virtual ~Virtual(); + virtual void virtualDefined(); + virtual void virtualInside() {} + virtual void virtualInlineDef(); + virtual inline void virtualInlineDecl(); +}; +template void Virtual::virtualDefined() {} +template inline void Virtual::virtualInlineDef() {} +template void Virtual::virtualInlineDecl() {} + +template struct Virtual; + + +// Export dynamic class template without key function. +// +// CHECK-DAG: @_ZTV13VirtualInlineI21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTS13VirtualInlineI21ExplicitInst_ExportedE = weak_odr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTI13VirtualInlineI21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualInlineI21ExplicitInst_ExportedEC1Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualInlineI21ExplicitInst_ExportedEC2Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualInlineI21ExplicitInst_ExportedEC1ERKS1_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualInlineI21ExplicitInst_ExportedEC2ERKS1_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr {{[^ ]*}} @_ZN13VirtualInlineI21ExplicitInst_ExportedEaSERKS1_({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN13VirtualInlineI21ExplicitInst_ExportedED0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN13VirtualInlineI21ExplicitInst_ExportedED1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN13VirtualInlineI21ExplicitInst_ExportedED2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +template +struct __declspec(dllexport) VirtualInline +{ + virtual ~VirtualInline() {} +}; + +template struct VirtualInline; + + +// Export extern dynamic class template. +// +// CHECK-DAG: @_ZTV13VirtualExternI21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTS13VirtualExternI21ExplicitInst_ExportedE = weak_odr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTI13VirtualExternI21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualExternI21ExplicitInst_ExportedEC1Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualExternI21ExplicitInst_ExportedEC2Ev({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualExternI21ExplicitInst_ExportedEC1ERKS1_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN13VirtualExternI21ExplicitInst_ExportedEC2ERKS1_({{[^\)]*}}) unnamed_addr #[[InlineExportGrp]] +// CHECK-DAG: define linkonce_odr {{[^ ]*}} @_ZN13VirtualExternI21ExplicitInst_ExportedEaSERKS1_({{[^\)]*}}) #[[InlineExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN13VirtualExternI21ExplicitInst_ExportedED0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN13VirtualExternI21ExplicitInst_ExportedED1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN13VirtualExternI21ExplicitInst_ExportedED2Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +template +struct __declspec(dllexport) VirtualExtern { + virtual ~VirtualExtern(); +}; +extern template struct VirtualExtern; + +template VirtualExtern::~VirtualExtern() {} +template struct VirtualExtern; + + +// Export dynamic class template with virtual inheritance. +// +// CHECK-DAG: @_ZTV12VirtualBase1I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTS12VirtualBase1I21ExplicitInst_ExportedE = weak_odr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTI12VirtualBase1I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// +// CHECK-DAG: @_ZTV12VirtualBase2I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTT12VirtualBase2I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTS12VirtualBase2I21ExplicitInst_ExportedE = weak_odr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTI12VirtualBase2I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: define weak_odr void @_ZTv0_n{{12|24}}_N12VirtualBase2I21ExplicitInst_ExportedED0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZTv0_n{{12|24}}_N12VirtualBase2I21ExplicitInst_ExportedED1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// +// CHECK-DAG: @_ZTV12VirtualBase3I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTT12VirtualBase3I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTS12VirtualBase3I21ExplicitInst_ExportedE = weak_odr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTI12VirtualBase3I21ExplicitInst_ExportedE = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: @_ZTC12VirtualBase3I21ExplicitInst_ExportedE0_12VirtualBase2IS0_E = weak_odr unnamed_addr constant {{.*}}, dllexport +// CHECK-DAG: define weak_odr void @_ZTv0_n{{12|24}}_N12VirtualBase3I21ExplicitInst_ExportedED0Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZTv0_n{{12|24}}_N12VirtualBase3I21ExplicitInst_ExportedED1Ev({{[^\)]*}}) unnamed_addr #[[ExportGrp]] +template struct __declspec(dllexport) VirtualBase1 { virtual ~VirtualBase1(); }; +template struct __declspec(dllexport) VirtualBase2 : virtual VirtualBase1 { virtual ~VirtualBase2(); }; +template struct __declspec(dllexport) VirtualBase3 : virtual VirtualBase2 { virtual ~VirtualBase3(); }; +template VirtualBase1::~VirtualBase1() {} +template VirtualBase2::~VirtualBase2() {} +template VirtualBase3::~VirtualBase3() {} + +template struct VirtualBase1; +template struct VirtualBase2; +template struct VirtualBase3; + + +// Inheritance +// +// Note: Specializations of exported class templates used as base class have to +// be exported explicitly with an instantiation. +// +// CHECK-DAG: define linkonce_odr void @_ZN7Derived1DEv({{[^\)]*}}) #[[ExportGrp]] +// CHECK-DAG: define weak_odr void @_ZN16InstantiatedBaseI7DerivedE2B3Ev({{[^\)]*}}) #[[ExportGrp]] +// CHECK-NOT: define weak_odr void @_ZN4BaseI7DerivedE2B1Ev({{[^\)]*}}) +// CHECK-NOT: define weak_odr void @_ZN12ExportedBaseI7DerivedE2B2Ev({{[^\)]*}}) +template +struct Base { + void B1() {} +}; + +template +struct __declspec(dllexport) ExportedBase { + void B2() {} +}; + +template +struct __declspec(dllexport) InstantiatedBase { + void B3() {} +}; + +struct __declspec(dllexport) Derived + : public Base, + public ExportedBase, + public InstantiatedBase { + void D() {} +}; + +template struct Base; +template struct __declspec(dllexport) InstantiatedBase; + + +// CHECK: attributes #[[InlineExportGrp]] = { dllexport inlinehint nounwind {{["\}]}} +// CHECK: attributes #[[ExportGrp]] = { dllexport nounwind {{["\}]}} +// CHECK: attributes #[[NotExportGrp]] = { nounwind {{["]}} Index: cfe/trunk/test/CodeGenCXX/dllimport-functions.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllimport-functions.cpp @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm %s -o - | FileCheck %s + +// Helper structs to make templates more expressive. +struct ImplicitInst_Imported {}; +struct ImplicitInst_NotImported {}; +struct ExplicitInst_Imported {}; +struct ExplicitInst_NotImported {}; +struct ExplicitSpec_Imported {}; +struct ExplicitSpec_NotImported {}; +struct ExplicitSpec_Inline_Imported {}; + +// Import function. +// CHECK-DAG: declare void @_Z8importedv() #[[ImportGrp:[0-9]+]] +// CHECK-DAG: declare void @_Z14externImportedv() #[[ImportGrp]] +__declspec(dllimport) void imported(); +__declspec(dllimport) extern void externImported(); + +// Export explicit inline functions. +// CHECK-DAG: declare void @_Z14inlineImportedv() #[[ImportGrp]] +// CHECK-DAG: declare void @_Z20externInlineImportedv() #[[ImportGrp]] +// CHECK-DAG_: define available_externally void @_Z20alwaysInlineImportedv() #[[InlineImportGrp]] +__declspec(dllimport) inline void inlineImported() {} +__declspec(dllimport) extern inline void externInlineImported() {} +__declspec(dllimport) __attribute__((always_inline)) inline void alwaysInlineImported() {} + + +// Redeclarations +// NB: MSVC issues a warning and makes redecl2/redecl3 dllexport. We follow GCC +// and drop the dllimport with a warning. +// CHECK-DAG: declare void @_Z7redecl1v() #[[ImportGrp]] +// CHECK-DAG: declare void @_Z7redecl2v() #[[NoImportGrp:[0-9]+]] +// CHECK-DAG: define void @_Z7redecl3v() #[[NoUnwindGrp:[0-9]+]] +__declspec(dllimport) void redecl1(); +__declspec(dllimport) void redecl1(); + +__declspec(dllimport) void redecl2(); + void redecl2(); + +__declspec(dllimport) void redecl3(); + void redecl3() {} + + +void use() { + imported(); + externImported(); + inlineImported(); + externInlineImported(); + alwaysInlineImported(); + redecl1(); + redecl2(); + redecl3(); +} + +// Imported function template. +// CHECK-DAG: declare void @_Z12importedTmplI21ImplicitInst_ImportedEvv() #[[ImportGrp]] +template __declspec(dllimport) void importedTmpl(); + +// Import specialization of an exported function template. +// CHECK-DAG: declare void @_Z12importedTmplI21ExplicitSpec_ImportedEvv() #[[ImportGrp]] +template<> __declspec(dllimport) void importedTmpl(); + +// Import specialization with explicit inline. +// CHECK-DAG: declare void @_Z12importedTmplI28ExplicitSpec_Inline_ImportedEvv() #[[ImportGrp]] +template<> __declspec(dllimport) inline void importedTmpl() {} + +// Not importing template specializations of an exported function template. +// CHECK-DAG: define linkonce_odr void @_Z12importedTmplI24ExplicitSpec_NotImportedEvv() #[[InlineGrp:[0-9]+]] +template<> inline void importedTmpl() {} + +void useTmpl() { + // Import implicit instantiation. + importedTmpl(); + importedTmpl(); + importedTmpl(); + importedTmpl(); +} + + +// Non-exported function template. +// CHECK-DAG: define weak_odr void @_Z15notImportedTmplI24ExplicitInst_NotImportedEvv() #[[InlineGrp]] +// CHECK-DAG: define linkonce_odr void @_Z15notImportedTmplI24ImplicitInst_NotImportedEvv() #[[InlineGrp]] +template inline void notImportedTmpl() {} + +// Not importing explicit instantiation. +template void notImportedTmpl(); + +// Import specialization of a non-exported function template. +// CHECK-DAG: declare void @_Z15notImportedTmplI21ExplicitSpec_ImportedEvv() #[[ImportGrp]] +template<> __declspec(dllimport) void notImportedTmpl(); + +// Import specialization of a non-exported function template. +// CHECK-DAG: declare void @_Z15notImportedTmplI28ExplicitSpec_Inline_ImportedEvv() #[[ImportGrp]] +template<> __declspec(dllimport) inline void notImportedTmpl() {} + +void useTmpl2() { + notImportedTmpl(); + notImportedTmpl(); + notImportedTmpl(); + notImportedTmpl(); +} + +// CHECK: attributes #[[NoUnwindGrp]] = { nounwind{{.*}} } +// CHECK: attributes #[[ImportGrp]] = { dllimport{{.*}} } +// CHECK: attributes #[[NoImportGrp]] = { "{{.*}} } +// CHECK: attributes #[[InlineGrp]] = { inlinehint{{.*}} } Index: cfe/trunk/test/CodeGenCXX/dllimport-globals.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllimport-globals.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm %s -o - | FileCheck %s + +// Import definitions. +// CHECK: @ImportedGlobal = external global i32, dllimport +__declspec(dllimport) int ImportedGlobal; + +// Declarations are not exported. +// CHECK: @ImportedExternGlobal = external global i32, dllimport +__declspec(dllimport) extern int ImportedExternGlobal; + +int use() { + return ImportedGlobal + ImportedExternGlobal; +} Index: cfe/trunk/test/CodeGenCXX/dllimport-members.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllimport-members.cpp @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -std=c++11 -emit-llvm %s -o - | FileCheck %s + +// CHECK: @_ZN1A17publicStaticFieldE = external global i32, dllimport + +// CHECK-DAG: define void @_ZN1A13ignoredNormalEv(%struct.A* %this) #[[NotImportGrp:[0-9]+]] +// CHECK-DAG: define void @_ZN1A19publicNormalDefinedEv(%struct.A* %this) #[[NotImportGrp]] +// CHECK-DAG: define void @_ZN1A20publicVirtualDefinedEv(%struct.A* %this) unnamed_addr #[[NotImportGrp]] +// CHECK-DAG: define void @_ZN1A19publicStaticDefinedEv() #[[NotImportGrp]] + +// CHECK-DAG: declare void @_ZN1A12publicNormalEv(%struct.A*) #[[ImportGrp:[0-9]+]] +// CHECK-DAG: declare void @_ZN1A18publicNormalInsideEv(%struct.A*) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A21publicNormalInlineDefEv(%struct.A*) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A22publicNormalInlineDeclEv(%struct.A*) #[[ImportGrp]] +// virtual not imported +// CHECK-DAG: declare void @_ZN1A12publicStaticEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A18publicStaticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A21publicStaticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A22publicStaticInlineDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A15protectedNormalEv(%struct.A*) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A15protectedStaticEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A13privateNormalEv(%struct.A*) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN1A13privateStaticEv() #[[ImportGrp]] + +// CHECK: attributes #[[NotImportGrp]] = { nounwind{{.*}} } +// CHECK: attributes #[[ImportGrp]] = { dllimport{{.*}} } + + +struct A { + void ignoredNormal(); + + __declspec(dllimport) void publicNormal(); + __declspec(dllimport) void publicNormalDefined(); + __declspec(dllimport) void publicNormalInside() {} + __declspec(dllimport) void publicNormalInlineDef(); + __declspec(dllimport) inline void publicNormalInlineDecl(); + __declspec(dllimport) virtual void publicVirtual(); + __declspec(dllimport) virtual void publicVirtualDefined(); + __declspec(dllimport) virtual void publicVirtualInside() {} + __declspec(dllimport) virtual void publicVirtualInlineDef(); + __declspec(dllimport) virtual inline void publicVirtualInlineDecl(); + __declspec(dllimport) static void publicStatic(); + __declspec(dllimport) static void publicStaticDefined(); + __declspec(dllimport) static void publicStaticInside() {} + __declspec(dllimport) static void publicStaticInlineDef(); + __declspec(dllimport) static inline void publicStaticInlineDecl(); + + __declspec(dllimport) static int publicStaticField; + __declspec(dllimport) static const int publicStaticConstField; + __declspec(dllimport) static const int publicStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + __declspec(dllimport) constexpr static int publicConstexprField = 2; +#endif + +protected: + __declspec(dllimport) void protectedNormal(); + __declspec(dllimport) static void protectedStatic(); + +private: + __declspec(dllimport) void privateNormal(); + __declspec(dllimport) static void privateStatic(); + + friend int use(A* Obj); +}; + void A::ignoredNormal() {} + void A::publicNormalDefined() {} +inline void A::publicNormalInlineDef() {} + void A::publicNormalInlineDecl() {} + void A::publicVirtualDefined() {} +inline void A::publicVirtualInlineDef() {} + void A::publicVirtualInlineDecl() {} + void A::publicStaticDefined() {} +inline void A::publicStaticInlineDef() {} + void A::publicStaticInlineDecl() {} + +template +T ref(T const& v) { return v; } + +int use(A* Obj) { + Obj->ignoredNormal(); + Obj->publicNormal(); + Obj->publicNormalDefined(); + Obj->publicNormalInside(); + Obj->publicNormalInlineDef(); + Obj->publicNormalInlineDecl(); + Obj->publicVirtual(); + Obj->publicVirtualDefined(); + Obj->publicVirtualInside(); + Obj->publicVirtualInlineDef(); + Obj->publicVirtualInlineDecl(); + Obj->publicStatic(); + Obj->publicStaticDefined(); + Obj->publicStaticInside(); + Obj->publicStaticInlineDef(); + Obj->publicStaticInlineDecl(); + Obj->protectedNormal(); + Obj->protectedStatic(); + Obj->privateNormal(); + Obj->privateStatic(); + return A::publicStaticField + ref(A::publicStaticConstField) + + A::publicStaticConstFieldInit + #if __has_feature(cxx_constexpr) + + A::publicConstexprField + #endif + ; +} Index: cfe/trunk/test/CodeGenCXX/dllimport-records.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllimport-records.cpp @@ -0,0 +1,425 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -emit-llvm %s -o - -O0 | FileCheck -check-prefix=NOP %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -std=c++11 -emit-llvm %s -o - -O0 | FileCheck -check-prefix=NOP %s +// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -emit-llvm %s -o - -O2 | FileCheck -check-prefix=OPT %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -std=c++11 -emit-llvm %s -o - -O2 | FileCheck -check-prefix=OPT %s + + +// Import non-dynamic class. +// +// NOP-DAG: @_ZN1A17publicStaticFieldE = external global i32, dllimport +// NOP-DAG: @_ZN1A22publicStaticConstFieldE = external constant i32, dllimport +// NOP-DAG: @_ZN1A20protectedStaticFieldE = external global i32, dllimport +// NOP-DAG: @_ZN1A25protectedStaticConstFieldE = external constant i32, dllimport +// NOP-DAG: @_ZN1A18privateStaticFieldE = external global i32, dllimport +// NOP-DAG: @_ZN1A23privateStaticConstFieldE = external constant i32, dllimport +// NOP-DAG: declare void @_ZN1A12publicNormalEv(%struct.A*) #[[ImportGrp:[0-9]+]] +// NOP-DAG: define void @_ZN1A19publicNormalDefinedEv(%struct.A* %this) #[[NoUnwindGrp:[0-9]+]] +// NOP-DAG: declare void @_ZN1A18publicNormalInsideEv(%struct.A*) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A21publicNormalInlineDefEv(%struct.A*) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A22publicNormalInlineDeclEv(%struct.A*) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A12publicStaticEv() #[[ImportGrp]] +// NOP-DAG: define void @_ZN1A19publicStaticDefinedEv() #[[NoUnwindGrp]] +// NOP-DAG: declare void @_ZN1A18publicStaticInsideEv() #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A21publicStaticInlineDefEv() #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A22publicStaticInlineDeclEv() #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A15protectedNormalEv(%struct.A*) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A15protectedStaticEv() #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A13privateNormalEv(%struct.A*) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN1A13privateStaticEv() #[[ImportGrp]] + +// OPT-DAG: @_ZN1A17publicStaticFieldE = external global i32, dllimport +// OPT-DAG: @_ZN1A20protectedStaticFieldE = external global i32, dllimport +// OPT-DAG: @_ZN1A18privateStaticFieldE = external global i32, dllimport +// OPT-DAG: define void @_ZN1A19publicNormalDefinedEv({{[^\)]*}}) #[[NoUnwindGrp:[0-9]+]] +// OPT-DAG: declare void @_ZN1A12publicNormalEv({{[^\)]*}}) #[[ImportGrp:[0-9]+]] +// OPT-DAG: define available_externally void @_ZN1A18publicNormalInsideEv({{[^\)]*}}) #[[ImportNoUnwindPureGrp:[0-9]+]] +// OPT-DAG: define available_externally void @_ZN1A21publicNormalInlineDefEv({{[^\)]*}}) #[[InlineImportGrp:[0-9]+]] +// OPT-DAG: define available_externally void @_ZN1A22publicNormalInlineDeclEv({{[^\)]*}}) #[[InlineImportGrp]] +// OPT-DAG: define void @_ZN1A19publicStaticDefinedEv() #[[NoUnwindGrp]] +// OPT-DAG: declare void @_ZN1A12publicStaticEv() #[[ImportGrp]] +// OPT-DAG: define available_externally void @_ZN1A18publicStaticInsideEv() #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN1A21publicStaticInlineDefEv() #[[InlineImportGrp]] +// OPT-DAG: define available_externally void @_ZN1A22publicStaticInlineDeclEv() #[[InlineImportGrp]] +// OPT-DAG: declare void @_ZN1A15protectedNormalEv({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare void @_ZN1A15protectedStaticEv() #[[ImportGrp]] +// OPT-DAG: declare void @_ZN1A13privateNormalEv({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare void @_ZN1A13privateStaticEv() #[[ImportGrp]] +struct __declspec(dllimport) A { +public: + void publicNormal(); + void publicNormalDefined(); + void publicNormalInside() {} + void publicNormalInlineDef(); + inline void publicNormalInlineDecl(); + static void publicStatic(); + static void publicStaticDefined(); + static void publicStaticInside() {} + static void publicStaticInlineDef(); + static inline void publicStaticInlineDecl(); + + int publicField; + static int publicStaticField; + static const int publicStaticConstField; + static const int publicStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int publicConstexprField = 2; +#endif + +protected: + void protectedNormal(); + static void protectedStatic(); + + int protectedField; + static int protectedStaticField; + static const int protectedStaticConstField; + static const int protectedStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int protectedConstexprField = 2; +#endif + +private: + void privateNormal(); + static void privateStatic(); + + int privateField; + static int privateStaticField; + static const int privateStaticConstField; + static const int privateStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int privateConstexprField = 2; +#endif + + template + friend void use(); +}; + void A::publicNormalDefined() {} // dllimport ignored +inline void A::publicNormalInlineDef() {} + void A::publicNormalInlineDecl() {} + void A::publicStaticDefined() {} // dllimport ignored +inline void A::publicStaticInlineDef() {} + void A::publicStaticInlineDecl() {} + + +struct X {}; + + +// Import special members. +// +// NOP-DAG: declare void @_ZN7SpecialC1Ev({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN7SpecialC1ERKS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN7SpecialC1EOS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN7SpecialC1E1X({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare {{[^ ]*}} @_ZN7SpecialaSERKS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare {{[^ ]*}} @_ZN7SpecialaSEOS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare {{[^ ]*}} @_ZN7SpecialaSE1X({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare i8 @_ZN7Specialcv1XEv({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN7SpecialD1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp:[0-9]+]] +// NOP-DAG: declare i8* @_ZN7SpecialnwE{{[jy)]}}({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare i8* @_ZN7SpecialnaE{{[jy)]}}({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN7SpecialdlEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// NOP-DAG: declare void @_ZN7SpecialdaEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// +// OPT-DAG: declare void @_ZN7SpecialC1Ev({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare void @_ZN7SpecialC1ERKS_({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare void @_ZN7SpecialC1EOS_({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare void @_ZN7SpecialC1E1X({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare {{[^ ]*}} @_ZN7SpecialaSERKS_({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare {{[^ ]*}} @_ZN7SpecialaSEOS_({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare {{[^ ]*}} @_ZN7SpecialaSE1X({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare i8 @_ZN7Specialcv1XEv({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare void @_ZN7SpecialD1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp:[0-9]+]] +// OPT-DAG: declare i8* @_ZN7SpecialnwE{{[jy)]}}({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare i8* @_ZN7SpecialnaE{{[jy)]}}({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: declare void @_ZN7SpecialdlEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// OPT-DAG: declare void @_ZN7SpecialdaEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +struct __declspec(dllimport) Special { + Special(); + Special(const Special&); + Special(Special&&); + Special(X); + Special& operator=(const Special&); + Special& operator=(Special&&); + Special& operator=(X); + operator X(); + ~Special(); + void* operator new(__SIZE_TYPE__); + void* operator new[](__SIZE_TYPE__); + void operator delete(void*); + void operator delete[](void*); +}; + + +// Import inline special members. +// +// NOP-DAG: declare void @_ZN13SpecialInlineC1Ev({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN13SpecialInlineC1ERKS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN13SpecialInlineC1EOS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN13SpecialInlineC1E1X({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare {{[^ ]*}} @_ZN13SpecialInlineaSERKS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare {{[^ ]*}} @_ZN13SpecialInlineaSEOS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare {{[^ ]*}} @_ZN13SpecialInlineaSE1X({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare i8 @_ZN13SpecialInlinecv1XEv({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN13SpecialInlineD1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// NOP-DAG: declare i8* @_ZN13SpecialInlinenwE{{[jy)]}}({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare i8* @_ZN13SpecialInlinenaE{{[jy)]}}({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN13SpecialInlinedlEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// NOP-DAG: declare void @_ZN13SpecialInlinedaEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// +// OPT-DAG: define available_externally void @_ZN13SpecialInlineC1Ev({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN13SpecialInlineC1ERKS_({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN13SpecialInlineC1EOS_({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN13SpecialInlineC1E1X({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally {{[^ ]*}} @_ZN13SpecialInlineaSERKS_({{[^\)]*}}) #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally {{[^ ]*}} @_ZN13SpecialInlineaSEOS_({{[^\)]*}}) #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally {{[^ ]*}} @_ZN13SpecialInlineaSE1X({{[^\)]*}}) #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally i8 @_ZN13SpecialInlinecv1XEv({{[^\)]*}}) #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN13SpecialInlineD1Ev({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally i8* @_ZN13SpecialInlinenwE{{[jy)]}}({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// OPT-DAG: define available_externally i8* @_ZN13SpecialInlinenaE{{[jy)]}}({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// OPT-DAG: define available_externally void @_ZN13SpecialInlinedlEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// OPT-DAG: define available_externally void @_ZN13SpecialInlinedaEPv({{[^\)]*}}) #[[ImportNoUnwindGrp]] +void* malloc(__SIZE_TYPE__ size); +void free(void* p); +struct __declspec(dllimport) SpecialInline { + SpecialInline() {} + SpecialInline(const SpecialInline&) {} + SpecialInline(SpecialInline&&) {} + SpecialInline(X) {} + SpecialInline& operator=(const SpecialInline&) { return *this; } + SpecialInline& operator=(SpecialInline&&) { return *this; } + SpecialInline& operator=(X) { return *this; } + operator X() { return X(); } + ~SpecialInline() {} + void* operator new(__SIZE_TYPE__ n) { return malloc(n); } + void* operator new[](__SIZE_TYPE__ n) { return malloc(n); } + void operator delete(void* p) { free(p); } + void operator delete[](void* p) { free(p); } +}; + + +// Import defaulted special members. +// +// NOP-DAG: declare void @_ZN9DefaultedC1Ev({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN9DefaultedC1ERKS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN9DefaultedC1EOS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare %struct.Defaulted* @_ZN9DefaultedaSERKS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare %struct.Defaulted* @_ZN9DefaultedaSEOS_({{[^\)]*}}) #[[ImportGrp]] +// NOP-DAG: declare void @_ZN9DefaultedD1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp]] +struct __declspec(dllimport) Defaulted { + Defaulted() = default; + Defaulted(const Defaulted&) = default; + Defaulted& operator=(const Defaulted&) = default; + Defaulted(Defaulted&&) = default; + Defaulted& operator=(Defaulted&&) = default; + ~Defaulted() = default; + Defaulted(X); + Defaulted& operator=(X); + operator X(); + Special v; // ensure non-trivial members +}; + + +// NOP-DAG: define available_externally void @_ZN7Attribs12AlwaysInlineEv({{[^\)]*}}) #[[AlwaysInlineImportGrp:[0-9]+]] +// NOP-DAG: declare void @_ZN7Attribs11NeverInlineEv({{[^\)]*}}) #[[ImportGrp]] +// OPT-DAG: define available_externally void @_ZN7Attribs12AlwaysInlineEv({{[^\)]*}}) #[[AlwaysInlineImportGrp:[0-9]+]] +// OPT-DAG: define available_externally void @_ZN7Attribs11NeverInlineEv({{[^\)]*}}) #[[NoInlineImportGrp:[0-9]+]] +struct __declspec(dllimport) Attribs { + __attribute__((always_inline)) void AlwaysInline() {} + __attribute__((noinline)) void NeverInline() {} +}; + + +// Import dynamic class with vtable and typeinfo. +// +// NOP-DAG: @_ZTI7Virtual = external constant {{.*}}, dllimport +// NOP-DAG: define void @_ZN7Virtual20publicVirtualDefinedEv({{[^\)]*}}) unnamed_addr #[[NoUnwindGrp]] +// via vtable: void @_ZN7Virtual13publicVirtualEv +// via vtable: void @_ZN7Virtual19publicVirtualInsideEv +// via vtable: void @_ZN7Virtual22publicVirtualInlineDefEv +// via vtable: void @_ZN7Virtual23publicVirtualInlineDeclEv +// +// OPT-DAG_: @_ZTV7Virtual = available_externally unnamed_addr constant {{.*}}, dllimport +// OPT-DAG_: @_ZTI7Virtual = external constant {{.*}}, dllimport +// OPT-DAG: define void @_ZN7Virtual20publicVirtualDefinedEv({{[^\)]*}}) unnamed_addr #[[NoUnwindGrp]] +// via vtable: void @_ZN7Virtual13publicVirtualEv +// OPT-DAG: define available_externally void @_ZN7Virtual19publicVirtualInsideEv({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN7Virtual22publicVirtualInlineDefEv({{[^\)]*}}) unnamed_addr #[[InlineImportGrp]] +// OPT-DAG: define available_externally void @_ZN7Virtual23publicVirtualInlineDeclEv({{[^\)]*}}) unnamed_addr #[[InlineImportGrp]] +struct __declspec(dllimport) Virtual { + virtual ~Virtual(); + virtual void publicVirtualDefined(); + virtual void publicVirtual(); + virtual void publicVirtualInside() {} + virtual void publicVirtualInlineDef(); + virtual inline void publicVirtualInlineDecl(); +}; + void Virtual::publicVirtualDefined() {} +inline void Virtual::publicVirtualInlineDef() {} + void Virtual::publicVirtualInlineDecl() {} + + +// Import dynamic class without key function. +// Note: vtable and rtti are not imported. +// +// NOP-DAG: @_ZTI13VirtualInline = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// NOP-DAG: @_ZTS13VirtualInline = linkonce_odr constant {{.*}}"{{$}} +// NOP-DAG: declare void @_ZN13VirtualInlineD1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp]] +// +// OPT-DAG: define available_externally void @_ZN13VirtualInlineD0Ev({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindGrp]] +// OPT-DAG: define available_externally void @_ZN13VirtualInlineD1Ev({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN13VirtualInlineD2Ev({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +// OPT-DAG: define available_externally void @_ZN13VirtualInline19publicVirtualInsideEv({{[^\)]*}}) unnamed_addr #[[ImportNoUnwindPureGrp]] +struct __declspec(dllimport) VirtualInline : virtual X { + virtual ~VirtualInline() {} + virtual void publicVirtualInside() {} +}; + + +// Import dynamic class with virtual inheritance. +// +// NOP-DAG: @_ZTI12VirtualBase1 = external constant {{.*}}, dllimport +// NOP-DAG: @_ZTI12VirtualBase2 = external constant {{.*}}, dllimport +// NOP-DAG: @_ZTI12VirtualBase3 = external constant {{.*}}, dllimport +struct __declspec(dllimport) VirtualBase1 { virtual ~VirtualBase1(); }; +struct __declspec(dllimport) VirtualBase2 : virtual VirtualBase1 { virtual ~VirtualBase2(); }; +struct __declspec(dllimport) VirtualBase3 : virtual VirtualBase2 { virtual ~VirtualBase3(); }; + + +// Import dynamic class without key function and with virtual inheritance. +// Note: vtable and rtti are not imported. +// +// NOP-DAG: @_ZTS18VirtualInlineBase1 = linkonce_odr constant {{.*}}"{{$}} +// NOP-DAG: @_ZTI18VirtualInlineBase1 = linkonce_odr unnamed_addr constant {{.*}}}{{$}} + +// NOP-DAG: @_ZTS18VirtualInlineBase2 = linkonce_odr constant {{.*}}"{{$}} +// NOP-DAG: @_ZTI18VirtualInlineBase2 = linkonce_odr unnamed_addr constant {{.*}}}{{$}} + +// NOP-DAG: @_ZTS18VirtualInlineBase3 = linkonce_odr constant {{.*}}"{{$}} +// NOP-DAG: @_ZTI18VirtualInlineBase3 = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +struct __declspec(dllimport) VirtualInlineBase1 { virtual ~VirtualInlineBase1() {} }; +struct __declspec(dllimport) VirtualInlineBase2 : virtual VirtualInlineBase1 { virtual ~VirtualInlineBase2() {} }; +struct __declspec(dllimport) VirtualInlineBase3 : virtual VirtualInlineBase2 { virtual ~VirtualInlineBase3() {} }; + + +template +T& declval(); + +namespace std { + // Required for typeid(). + class type_info {}; +} + +template int useField(T const& v) { return v + 1; } +template int useField(T& v) { return v++; } + +template +void use() { + T& Obj = declval(); + Obj.publicNormal(); + Obj.publicNormalDefined(); + Obj.publicNormalInside(); + Obj.publicNormalInlineDef(); + Obj.publicNormalInlineDecl(); + Obj.publicStatic(); + Obj.publicStaticDefined(); + Obj.publicStaticInside(); + Obj.publicStaticInlineDef(); + Obj.publicStaticInlineDecl(); + + Obj.protectedNormal(); + Obj.protectedStatic(); + + Obj.privateNormal(); + Obj.privateStatic(); + + useField(Obj.publicField); + useField(T::publicStaticField); + useField(T::publicStaticConstField); + useField(T::publicStaticConstFieldInit); +#if __has_feature(cxx_constexpr) + useField(T::publicConstexprField); +#endif + + useField(Obj.protectedField); + useField(T::protectedStaticField); + useField(T::protectedStaticField); + useField(T::protectedStaticConstField); + useField(T::protectedStaticConstFieldInit); +#if __has_feature(cxx_constexpr) + useField(T::protectedConstexprField); +#endif + + useField(Obj.privateField); + useField(T::privateStaticField); + useField(T::privateStaticConstField); + useField(T::privateStaticConstFieldInit); +#if __has_feature(cxx_constexpr) + useField(T::privateConstexprField); +#endif +} + +template +void useSpecial() { + X x; + T v1; // ctor + + T v2(static_cast(v1)); // copy-ctor + v2 = static_cast(v1); // copy-assignment + + T v3(static_cast(v1)); // move-ctor + v3 = static_cast(v1); // move-assignment + + T v4(x); // init from x + v4 = x; // copy from x + x = v4; // conversion to x + + delete new T(); + delete[] new T[1]; +} + +template +void useVirtual() +{ + delete new T(); + delete[] new T[1]; + (void)typeid(T); +} + +void dummy() { + use(); + + useSpecial(); + useSpecial(); + useSpecial(); + + declval().AlwaysInline(); + declval().NeverInline(); + + useVirtual(); + declval().publicVirtual(); + declval().publicVirtualDefined(); + declval().publicVirtualInside(); + declval().publicVirtualInlineDef(); + declval().publicVirtualInlineDecl(); + + useVirtual(); + useVirtual(); + useVirtual(); + useVirtual(); + useVirtual(); + useVirtual(); + useVirtual(); +} + +// NOP-DAG: attributes #[[NoUnwindGrp]] = { nounwind {{["\}]}} +// NOP-DAG: attributes #[[AlwaysInlineImportGrp]] = { alwaysinline dllimport nounwind {{["\}]}} +// NOP-DAG: attributes #[[ImportGrp]] = { dllimport {{["\}]}} +// NOP-DAG: attributes #[[ImportNoUnwindGrp]] = { dllimport nounwind {{["\}]}} + +// OPT-DAG: attributes #[[ImportNoUnwindPureGrp]] = { dllimport nounwind readnone {{["\}]}} +// OPT-DAG: attributes #[[NoUnwindGrp]] = { nounwind readnone {{["\}]}} +// OPT-DAG: attributes #[[InlineImportGrp]] = { dllimport inlinehint nounwind readnone {{["\}]}} +// OPT-DAG: attributes #[[AlwaysInlineImportGrp]] = { alwaysinline dllimport nounwind readnone {{["\}]}} +// OPT-DAG: attributes #[[NoInlineImportGrp]] = { dllimport noinline nounwind readnone {{["\}]}} +// OPT-DAG: attributes #[[ImportNoUnwindGrp]] = { dllimport nounwind {{["\}]}} +// OPT-DAG: attributes #[[ImportGrp]] = { dllimport {{["\}]}} Index: cfe/trunk/test/CodeGenCXX/dllimport-templates.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/CodeGenCXX/dllimport-templates.cpp @@ -0,0 +1,372 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -std=c++11 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-win32 -std=c++11 -emit-llvm %s -o - | FileCheck %s + +// Helper structs to make template specializations more expressive. +struct ImplicitInst_Imported {}; +struct ImplicitInst_NotImported {}; +struct ExplicitInst_Imported {}; +struct ExplicitInst_ExplicitImported {}; +struct ExplicitSpec_Imported {}; +struct ExplicitSpec_NotImported {}; + +// Imported class template. +// +// CHECK-DAG: @_ZN3ImpI21ImplicitInst_ImportedE11staticFieldE = external global i32, dllimport +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE13normalDefinedEv({{[^\)]*}}) #[[ImportGrp:[0-9]+]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE10normalDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE12normalInsideEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE15normalInlineDefEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE16normalInlineDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE13staticDefinedEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE10staticDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE12staticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE15staticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ImplicitInst_ImportedE16staticInlineDeclEv() #[[ImportGrp]] +template +struct __declspec(dllimport) Imp { + void normalDefined(); + void normalDecl(); + void normalInside() {} + void normalInlineDef(); + inline void normalInlineDecl(); + static void staticDefined(); + static void staticDecl(); + static void staticInside() {} + static void staticInlineDef(); + static inline void staticInlineDecl(); + static int staticField; +}; +template void Imp::normalDefined() {} +template inline void Imp::normalInlineDef() {} +template void Imp::normalInlineDecl() {} +template void Imp::staticDefined() {} +template inline void Imp::staticInlineDef() {} +template void Imp::staticInlineDecl() {} + +// Import explicit instantiation of an imported class template. +// +// CHECK-DAG: @_ZN3ImpI21ExplicitInst_ImportedE11staticFieldE = external global i32, dllimport +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE13normalDefinedEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE10normalDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE12normalInsideEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE15normalInlineDefEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE16normalInlineDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE13staticDefinedEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE10staticDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE12staticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE15staticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitInst_ImportedE16staticInlineDeclEv() #[[ImportGrp]] +template struct Imp; + +// Explicitly import explicit instantiation of an imported class template. +// +// CHECK-DAG: @_ZN3ImpI29ExplicitInst_ExplicitImportedE11staticFieldE = external global i32, dllimport +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE13normalDefinedEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE10normalDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE12normalInsideEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE15normalInlineDefEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE16normalInlineDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE13staticDefinedEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE10staticDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE12staticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE15staticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI29ExplicitInst_ExplicitImportedE16staticInlineDeclEv() #[[ImportGrp]] +template struct __declspec(dllimport) Imp; + + +// Import a specialization of a class template. +// +// CHECK-DAG: @_ZN3ImpI21ExplicitSpec_ImportedE11staticFieldE = external global i32, dllimport +// CHECK-DAG: define void @_ZN3ImpI21ExplicitSpec_ImportedE13normalDefinedEv({{[^\)]*}}) #[[NoUnwindGrp:[0-9]+]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE10normalDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE12normalInsideEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE15normalInlineDefEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE16normalInlineDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: define void @_ZN3ImpI21ExplicitSpec_ImportedE13staticDefinedEv() #[[NoUnwindGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE10staticDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE12staticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE15staticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN3ImpI21ExplicitSpec_ImportedE16staticInlineDeclEv() #[[ImportGrp]] +template<> +struct __declspec(dllimport) Imp { + void normalDefined(); + void normalDecl(); + void normalInside() {} + void normalInlineDef(); + inline void normalInlineDecl(); + static void staticDefined(); + static void staticDecl(); + static void staticInside() {} + static void staticInlineDef(); + static inline void staticInlineDecl(); + static int staticField; +}; + void Imp::normalDefined() {} +inline void Imp::normalInlineDef() {} + void Imp::normalInlineDecl() {} + void Imp::staticDefined() {} +inline void Imp::staticInlineDef() {} + void Imp::staticInlineDecl() {} + + +// Not importing specialization of an exported class template. +// CHECK-DAG: define void @_ZN3ImpI24ExplicitSpec_NotImportedE10normalDeclEv({{[^\)]*}}) #[[NoUnwindGrp]] +template<> +struct Imp { + void normalDecl(); +}; +void Imp::normalDecl() {} + + +// Non-imported class template. +template +struct NotImp { + void normalDefined(); + void normalDecl(); + void normalInside() {} + void normalInlineDef(); + inline void normalInlineDecl(); + static void staticDefined(); + static void staticDecl(); + static void staticInside() {} + static void staticInlineDef(); + static inline void staticInlineDecl(); + static int staticField; +}; +template void NotImp::normalDefined() {} +template inline void NotImp::normalInlineDef() {} +template void NotImp::normalInlineDecl() {} +template void NotImp::staticDefined() {} +template inline void NotImp::staticInlineDef() {} +template void NotImp::staticInlineDecl() {} + + +// Explicitly import explicit instantiation of a non-imported class template. +// +// CHECK-DAG: @_ZN6NotImpI21ExplicitInst_ImportedE11staticFieldE = external global i32, dllimport +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE13normalDefinedEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE10normalDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE12normalInsideEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE15normalInlineDefEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE16normalInlineDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE13staticDefinedEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE10staticDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE12staticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE15staticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6NotImpI21ExplicitInst_ImportedE16staticInlineDeclEv() #[[ImportGrp]] +template struct __declspec(dllimport) NotImp; + + +// Non-imported class template with imported members. +// +// CHECK-DAG: @_ZN6ImpMemI21ImplicitInst_ImportedE11staticFieldE = external global i32, dllimport +// CHECK-DAG: define linkonce_odr void @_ZN6ImpMemI21ImplicitInst_ImportedE13normalDefinedEv({{[^\)]*}}s) #[[NoUnwindGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE10normalDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE12normalInsideEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE15normalInlineDefEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE16normalInlineDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: define linkonce_odr void @_ZN6ImpMemI21ImplicitInst_ImportedE13staticDefinedEv() #[[NoUnwindGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE10staticDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE12staticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE15staticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ImplicitInst_ImportedE16staticInlineDeclEv() #[[ImportGrp]] +template +struct ImpMem { + __declspec(dllimport) void normalDecl(); + __declspec(dllimport) void normalDefined(); + __declspec(dllimport) void normalInside() {} + __declspec(dllimport) void normalInlineDef(); + __declspec(dllimport) inline void normalInlineDecl(); + __declspec(dllimport) static void staticDecl(); + __declspec(dllimport) static void staticDefined(); + __declspec(dllimport) static void staticInside() {} + __declspec(dllimport) static void staticInlineDef(); + __declspec(dllimport) static inline void staticInlineDecl(); + __declspec(dllimport) static int staticField; + void ignoredNormal(); +}; +template void ImpMem::normalDefined() {} +template inline void ImpMem::normalInlineDef() {} +template void ImpMem::normalInlineDecl() {} +template void ImpMem::staticDefined() {} +template inline void ImpMem::staticInlineDef() {} +template void ImpMem::staticInlineDecl() {} +template void ImpMem::ignoredNormal() {} + + +// Import selected members of explicit instantiation of non-imported class template. +// +// CHECK-DAG: @_ZN6ImpMemI21ExplicitInst_ImportedE11staticFieldE = external global i32, dllimport +// CHECK-DAG: define weak_odr void @_ZN6ImpMemI21ExplicitInst_ImportedE13normalDefinedEv({{[^\)]*}}) #[[NoUnwindGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE10normalDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE12normalInsideEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE15normalInlineDefEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE16normalInlineDeclEv({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ImpMemI21ExplicitInst_ImportedE13staticDefinedEv() #[[NoUnwindGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE10staticDeclEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE12staticInsideEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE15staticInlineDefEv() #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN6ImpMemI21ExplicitInst_ImportedE16staticInlineDeclEv() #[[ImportGrp]] +// CHECK-DAG: define weak_odr void @_ZN6ImpMemI21ExplicitInst_ImportedE13ignoredNormalEv({{[^\)]*}}) #[[NoUnwindGrp]] +template struct ImpMem; + + +// Import dynamic class template. +// Note: vtable and rtti are not imported. +// +// CHECK-DAG: @_ZTI7VirtualI21ImplicitInst_ImportedE = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// CHECK-DAG: @_ZTS7VirtualI21ImplicitInst_ImportedE = linkonce_odr constant {{.*}}"{{$}} +// CHECK-DAG: declare void @_ZN7VirtualI21ImplicitInst_ImportedED1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp:[0-9]+]] +template +struct __declspec(dllimport) Virtual +{ + virtual ~Virtual(); + virtual void virtualDecl(); + virtual void virtualInside() {} + virtual void virtualInlineDef(); + virtual inline void virtualInlineDecl(); +}; +template inline void Virtual::virtualInlineDef() {} +template void Virtual::virtualInlineDecl() {} + + +// Import dynamic class template without key function. +// Note: vtable and rtti are not imported. +// +// CHECK-DAG: @_ZTI13VirtualInlineI21ImplicitInst_ImportedE = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// CHECK-DAG: @_ZTS13VirtualInlineI21ImplicitInst_ImportedE = linkonce_odr constant {{.*}}"{{$}} +// CHECK-DAG: declare void @_ZN13VirtualInlineI21ImplicitInst_ImportedED1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp]] +template +struct __declspec(dllimport) VirtualInline +{ + virtual ~VirtualInline() {} +}; + + +// Import extern dynamic class template. +// +// CHECK-DAG: @_ZTI13VirtualExternI21ImplicitInst_ImportedE = external constant {{.*}}, dllimport +// CHECK-DAG: declare void @_ZN13VirtualExternI21ImplicitInst_ImportedED1Ev({{[^\)]*}}) #[[ImportNoUnwindGrp]] +template +struct __declspec(dllimport) VirtualExtern { + virtual ~VirtualExtern(); +}; +extern template struct VirtualExtern; + + +// Import dynamic class template with virtual inheritance. +// Note: vtable and rtti are not imported. +// +// CHECK-DAG: @_ZTI12VirtualBase1I21ImplicitInst_ImportedE = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// CHECK-DAG: @_ZTS12VirtualBase1I21ImplicitInst_ImportedE = linkonce_odr constant {{.*}}"{{$}} +// +// CHECK-DAG: @_ZTI12VirtualBase2I21ImplicitInst_ImportedE = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// CHECK-DAG: @_ZTS12VirtualBase2I21ImplicitInst_ImportedE = linkonce_odr constant {{.*}}"{{$}} +// +// CHECK-DAG: @_ZTI12VirtualBase3I21ImplicitInst_ImportedE = linkonce_odr unnamed_addr constant {{.*}}}{{$}} +// CHECK-DAG: @_ZTS12VirtualBase3I21ImplicitInst_ImportedE = linkonce_odr constant {{.*}}"{{$}} +template struct __declspec(dllimport) VirtualBase1 { virtual ~VirtualBase1(); }; +template struct __declspec(dllimport) VirtualBase2 : virtual VirtualBase1 { virtual ~VirtualBase2(); }; +template struct __declspec(dllimport) VirtualBase3 : virtual VirtualBase2 { virtual ~VirtualBase3(); }; +template inline VirtualBase1::~VirtualBase1() {} +template inline VirtualBase2::~VirtualBase2() {} +template inline VirtualBase3::~VirtualBase3() {} + + +// Inheritance +// +// CHECK-DAG: define linkonce_odr void @_ZN12ExportedBase2B4Ev({{[^\)]*}}) #[[ExportGrp:[0-9]+]] +// CHECK-DAG: declare void @_ZN4Base2B1Ev({{[^\)]*}}) #[[NoImportGrp:[0-9]+]] +// CHECK-DAG: declare void @_ZN8BaseTmplI10DerivedImpE2B2Ev({{[^\)]*}}) #[[NoImportGrp]] +// CHECK-DAG: declare void @_ZN12ImportedBaseI10DerivedImpE2B3Ev({{[^\)]*}}) #[[ImportGrp]] +// CHECK-DAG: declare void @_ZN10DerivedImp1DEv({{[^\)]*}}) #[[ImportGrp]] +struct Base { void B1(); }; + +template +struct BaseTmpl { void B2(); }; + +template +struct __declspec(dllimport) ImportedBase { void B3(); }; + +struct __declspec(dllexport) ExportedBase { void B4() {} }; + +struct __declspec(dllimport) DerivedImp + : public Base, + public BaseTmpl, + public ImportedBase, + public ExportedBase { + void D(); +}; + + +template +T& declval(); + +namespace std +{ + struct type_info { + virtual ~type_info() {} + const char *__type_name; + }; +} + +template +void useClass() { + T& Obj = declval(); + Obj.normalDecl(); + Obj.normalDefined(); + Obj.normalInside(); + Obj.normalInlineDef(); + Obj.normalInlineDecl(); + Obj.staticDecl(); + Obj.staticDefined(); + Obj.staticInside(); + Obj.staticInlineDef(); + Obj.staticInlineDecl(); + T::staticField = 1; +} + +template +char const* useVirtual() { + delete new T(); + delete[] new T[1]; + (void)typeid(T); + return typeid(T).__type_name; +} + +void use() { + useClass >(); + useClass >(); + useClass >(); + useClass >(); + + useClass >(); + useClass >(); + + useClass >(); + useClass >(); + + useVirtual >(); + declval >().virtualDecl(); + declval >().virtualInside(); + declval >().virtualInlineDef(); + declval >().virtualInlineDecl(); + + useVirtual >(); + useVirtual >(); + useVirtual >(); + useVirtual >(); + useVirtual >(); + + declval().B1(); + declval().B2(); + declval().B3(); + declval().B4(); + declval().D(); +} + +// CHECK: attributes #[[NoUnwindGrp]] = { nounwind {{["\}]}} +// CHECK: attributes #[[ExportGrp]] = { dllexport nounwind {{["\}]}} +// CHECK: attributes #[[NoImportGrp]] = { {{["\}]}} +// CHECK: attributes #[[ImportGrp]] = { dllimport {{["\}]}} +// CHECK: attributes #[[ImportNoUnwindGrp]] = { dllimport nounwind {{["\}]}} Index: cfe/trunk/test/Rewriter/dllimport-typedef.c =================================================================== --- cfe/trunk/test/Rewriter/dllimport-typedef.c +++ cfe/trunk/test/Rewriter/dllimport-typedef.c @@ -10,8 +10,8 @@ void bar() { return 1; } // CHECK-NEG: error: void function 'bar' should not return a value -// CHECK-NEG: 1 error generated -// CHECK-POS: warning: 'dllimport' attribute only applies to variables and functions +// CHECK-NEG: {{^}}1 error generated +// CHECK-POS: warning: 'dllimport' attribute only applies to variables, functions and tag types // CHECK-POS: error: void function 'bar' should not return a value // CHECK-POS: 1 warning and 1 error generated Index: cfe/trunk/test/Rewriter/missing-dllimport.c =================================================================== --- cfe/trunk/test/Rewriter/missing-dllimport.c +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-NEG %s -// RUN: %clang_cc1 -triple i686-pc-win32 -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-POS %s - -// Do not report that 'foo()' is redeclared without dllimport attribute with -fms-extensions -// specified. Addresses . - -__declspec(dllimport) int __cdecl foo(void); -inline int __cdecl foo() { return 0; } - -// This function is added just to trigger a diagnostic. This way we can test how many -// diagnostics we expect. -void bar() { return 1; } - -// CHECK-NEG: error: void function 'bar' should not return a value -// CHECK-NEG: 1 error generated -// CHECK-POS: warning: 'foo' redeclared without dllimport attribute: previous dllimport ignored -// CHECK-POS: error: void function 'bar' should not return a value -// CHECK-POS: 1 warning and 1 error generated - Index: cfe/trunk/test/Sema/dllexport.c =================================================================== --- /dev/null +++ cfe/trunk/test/Sema/dllexport.c @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify -std=c99 %s + +// Invalid decls. +__declspec(dllexport) typedef int typedef1; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllexport) int typedef2; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +typedef int __declspec(dllexport) typedef3; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllexport) void (*FunTy)(); // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +enum __declspec(dllexport) Enum { EnumVal }; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} + + +// Globals + +// Export definitions. +__declspec(dllexport) int GlobalInit = 1; + +// Export definitions without initializer. +__declspec(dllexport) int GlobalDef; + +// Force declaration, then export when defined. +__declspec(dllexport) extern int GlobalDeclInit; +int GlobalDeclInit = 2; + +// Declarations are not exported. +__declspec(dllexport) extern int GlobalDecl; + +// Reject inconsistent redeclarations. +extern int GlobalRedecl; // expected-note{{previous declaration is here}} +__declspec(dllexport) extern int GlobalRedecl; // expected-error{{'GlobalRedecl' redeclared with different DLL attributes}} + +// External linkage is required. +__declspec(dllexport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage to be exported}} + +void functionScope() { + __declspec(dllexport) int LocalVar; // expected-error{{'LocalVar' must have external linkage to be exported}} + __declspec(dllexport) extern int ExternLocalVar; + __declspec(dllexport) static int StaticLocalVar; // expected-error{{'StaticLocalVar' must have external linkage to be exported}} +} + + +// Functions + +// Export function. +__attribute__((dllexport)) void defA() {} // Sanity check with __attribute__ +__declspec(dllexport) void defB() {} + +// Declare and define an exported function. +__declspec(dllexport) void declDef(); +void declDef() {} + +// Export inline functions. +// TODO: Disallow C99 inline. +__declspec(dllexport) inline void inlineFunc() {} + +// Export ignored for declarations. +__declspec(dllexport) void decl(); + +// Redeclarations +__declspec(dllexport) void redecl1(); +__declspec(dllexport) void redecl1(); + +__declspec(dllexport) void redecl2(); + void redecl2(); + +__declspec(dllexport) void redecl3(); + void redecl3() {} + + void redecl4(); // expected-note{{previous declaration is here}} +__declspec(dllexport) void redecl4(); // expected-error{{'redecl4' redeclared with different DLL attributes}} + + void redecl5(); // expected-note{{previous declaration is here}} +__declspec(dllexport) inline void redecl5() {} // expected-error{{'redecl5' redeclared with different DLL attributes}} + + +// dllexport takes precedence over the dllimport if both are specified. +__attribute__((dllimport, dllexport)) extern int PrecedenceGlobal1A; // expected-warning{{dllimport attribute ignored}} +__declspec(dllimport) __declspec(dllexport) extern int PrecedenceGlobal1B; // expected-warning{{dllimport attribute ignored}} + +__attribute__((dllexport, dllimport)) extern int PrecedenceGlobal2A; // expected-warning{{dllimport attribute ignored}} +__declspec(dllexport) __declspec(dllimport) extern int PrecedenceGlobal2B; // expected-warning{{dllimport attribute ignored}} + +__declspec(dllexport) extern int PrecedenceGlobalRececl1; +__declspec(dllimport) extern int PrecedenceGlobalRececl1; // expected-warning{{dllimport attribute ignored}} + +__declspec(dllimport) extern int PrecedenceGlobalRedecl2; // expected-warning{{dllimport attribute ignored}} +__declspec(dllexport) extern int PrecedenceGlobalRedecl2; + +__attribute__((dllexport)) extern int PrecedenceGlobalMixed1; +__declspec(dllimport) extern int PrecedenceGlobalMixed1; // expected-warning{{dllimport attribute ignored}} + +__attribute__((dllimport)) extern int PrecedenceGlobalMixed2; // expected-warning{{dllimport attribute ignored}} +__declspec(dllexport) extern int PrecedenceGlobalMixed2; + +void __attribute__((dllimport, dllexport)) precedence1A(); // expected-warning{{dllimport attribute ignored}} +void __declspec(dllimport) __declspec(dllexport) precedence1B(); // expected-warning{{dllimport attribute ignored}} + +void __attribute__((dllexport, dllimport)) precedence2A(); // expected-warning{{dllimport attribute ignored}} +void __declspec(dllexport) __declspec(dllimport) precedence2B(); // expected-warning{{dllimport attribute ignored}} + +void __declspec(dllimport) precedenceRedecl1(); // expected-warning{{dllimport attribute ignored}} +void __declspec(dllexport) precedenceRedecl1(); + +void __declspec(dllexport) precedenceRedecl2(); +void __declspec(dllimport) precedenceRedecl2(); // expected-warning{{dllimport attribute ignored}} Index: cfe/trunk/test/Sema/dllimport-dllexport.c =================================================================== --- cfe/trunk/test/Sema/dllimport-dllexport.c +++ /dev/null @@ -1,48 +0,0 @@ -// RUN: %clang_cc1 -triple i386-mingw32 -fsyntax-only -verify %s -// RUN: %clang_cc1 -triple x86_64-mingw32 -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 variables and functions}} - -typedef int __attribute__((dllimport)) type7; // expected-warning{{'dllimport' attribute only applies to variables and functions}} - -void __attribute__((dllimport)) foo6(); -void foo6(){} // expected-warning {{'foo6' redeclared without dllimport attribute: previous dllimport ignored}} - -// PR6269 -inline void __declspec(dllexport) foo7(){} // expected-warning{{dllexport attribute ignored}} -inline void __declspec(dllimport) foo8(){} // expected-warning{{dllimport attribute ignored}} - -void __declspec(dllimport) foo9(){} // expected-error{{dllimport attribute can be applied only to symbol declaration}} - -void __declspec(dllimport) __declspec(dllexport) foo10(); // expected-warning{{dllimport attribute ignored}} - -void __declspec(dllexport) foo11(); -void __declspec(dllimport) foo11(); // expected-warning{{dllimport attribute ignored}} - -typedef int __declspec(dllexport) type1; // expected-warning{{'dllexport' attribute only applies to variables and functions}} - -typedef int __declspec(dllimport) type2; // expected-warning{{'dllimport' attribute only applies to variables and functions}} - -void __declspec(dllimport) foo12(); -void foo12(){} // expected-warning {{'foo12' redeclared without dllimport attribute: previous dllimport ignored}} - -void __attribute__((dllimport)) foo13(); // expected-warning{{dllimport attribute ignored}} -void __attribute__((dllexport)) foo13(); - -extern int foo14 __attribute__((dllexport)); -extern int foo14 __attribute__((dllimport)); // expected-warning{{dllimport attribute ignored}} - -__declspec(dllimport) int foo15 = 54; // expected-warning{{'dllimport' attribute cannot be specified on a definition}} - -extern __declspec(dllimport) int foo17; -int foo17 = 54; // expected-warning{{'dllimport' attribute cannot be specified on a definition}} Index: cfe/trunk/test/Sema/dllimport.c =================================================================== --- /dev/null +++ cfe/trunk/test/Sema/dllimport.c @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify -std=c99 %s + +// Invalid decls. +__declspec(dllimport) typedef int typedef1; // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllimport) int typedef2; // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} +typedef int __declspec(dllimport) typedef3; // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllimport) void (*FunTy)(); // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} + + +// Globals + +// Import declarations. +__declspec(dllimport) int GlobalDecl; +__declspec(dllimport) extern int ExternGlobalDecl; + +// Not allowed on definitions. +__declspec(dllimport) int GlobalDef = 3; // expected-error{{'dllimport' attribute cannot be specified on a definition}} + +// Reject inconsistent redeclarations. +extern int GlobalRedecl1; // expected-note{{previous declaration is here}} +__declspec(dllimport) extern int GlobalRedecl1; // expected-error{{'GlobalRedecl1' redeclared with different DLL attributes}} + +// NB: MSVC issues a warning and makes GlobalRedecl2 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) extern int GlobalRedecl2; // expected-note{{previous attribute is here}} +extern int GlobalRedecl2; // expected-warning{{'GlobalRedecl2' redeclared without dllimport attribute: previous dllimport ignored}} + +// Drop dllimport on inconsistent attributes. +__attribute__((dllimport)) extern int impExternVarA; // expected-note{{previous attribute is here}} +__declspec(dllimport) extern int impExternVarB; // expected-note{{previous attribute is here}} +extern int impExternVarA; // expected-warning{{'impExternVarA' redeclared without dllimport attribute: previous dllimport ignored}} +extern int impExternVarB; // expected-warning{{'impExternVarB' redeclared without dllimport attribute: previous dllimport ignored}} + +// Extern linkage is required. +__declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage to be imported}} + +void functionScope() { + __declspec(dllimport) int LocalVar; + __declspec(dllimport) extern int ExternLocalVar; + __declspec(dllimport) static int StaticLocalVar; // expected-error{{'StaticLocalVar' must have external linkage to be imported}} +} + + +// Functions + +// Import function declaration. +__attribute__((dllimport)) void declA(); // Sanity check with __attribute__ +__declspec(dllimport) void declB(); + +// Not allowed on function definitions. +__declspec(dllimport) void def() {} // expected-error{{'dllimport' attribute cannot be specified on a definition}} + +#if __STDC_VERSION__ >= 199901L +// Not allowed on C99 inline functions. +__declspec(dllimport) inline void inlineFunc() {} +#endif // C99 + +// Redeclarations +__declspec(dllimport) void redecl1(); +__declspec(dllimport) void redecl1(); + +// NB: MSVC issues a warning and makes redecl2/redecl3 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) void redecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + void redecl2(); // expected-warning{{'redecl2' redeclared without dllimport attribute: previous dllimport ignored}} + +__declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + void redecl3() {} // expected-warning{{'redecl3' redeclared without dllimport attribute: previous dllimport ignored}} + + void redecl4(); // expected-note{{previous declaration is here}} +__declspec(dllimport) void redecl4(); // expected-error{{'redecl4' redeclared with different DLL attributes}} Index: cfe/trunk/test/SemaCXX/MicrosoftExtensions.cpp =================================================================== --- cfe/trunk/test/SemaCXX/MicrosoftExtensions.cpp +++ cfe/trunk/test/SemaCXX/MicrosoftExtensions.cpp @@ -123,10 +123,10 @@ class AAA { __declspec(dllimport) void f(void) { } -void f2(void); +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{{'f2' redeclared with different DLL attributes}} // expected-error {{'dllimport' attribute cannot be specified on a definition}} } Index: cfe/trunk/test/SemaCXX/dllexport.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/SemaCXX/dllexport.cpp @@ -0,0 +1,399 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -x c++ -verify -fsyntax-only -Wmissing-dllexport %s +// RUN: %clang_cc1 -triple i386-pc-win32 -x c++ -verify -fsyntax-only -Wmissing-dllexport -std=c++11 %s + +// Helper structs to make template specializations more expressive. +struct ImplicitInst_Exported {}; +struct ImplicitInst_NotExported {}; +struct ExplicitSpec_Exported {}; +struct ExplicitSpec_Inline_Exported {}; +struct ExplicitSpec_NotExported {}; + + +// Invalid decls. +__declspec(dllexport) typedef int typedef1; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllexport) int typedef2; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +typedef int __declspec(dllexport) typedef3; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllexport) void (*FunTy)(); // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +enum __declspec(dllexport) Enum {}; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +#if __has_feature(cxx_strong_enums) + enum class __declspec(dllexport) EnumClass {}; // expected-warning{{'dllexport' attribute only applies to variables, functions and tag types}} +#endif + + +// Globals + +// Export definitions. +__declspec(dllexport) int GlobalInit = 1; + +// Export definitions without initializer. +__declspec(dllexport) int GlobalDef; + +// Force declaration, then export when defined. +__declspec(dllexport) extern int GlobalDeclInit; +int GlobalDeclInit = 2; + +// Declarations are not exported. +__declspec(dllexport) extern int GlobalDecl; + +// Reject inconsistent redeclarations. +extern int GlobalRedecl; // expected-note{{previous declaration is here}} +__declspec(dllexport) extern int GlobalRedecl; // expected-error{{'GlobalRedecl' redeclared with different DLL attributes}} + +// External linkage is required. +__declspec(dllexport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage to be exported}} + +void functionScope() { + __declspec(dllexport) int LocalVar; // expected-error{{'LocalVar' must have external linkage to be exported}} + __declspec(dllexport) extern int ExternLocalVar; + __declspec(dllexport) static int StaticLocalVar; // expected-error{{'StaticLocalVar' must have external linkage to be exported}} +} + + + +// Functions + +// Export function. +__attribute__((dllexport)) void defA() {} // Sanity check with __attribute__ +__declspec(dllexport) void defB() {} + +// Declare and define an exported function. +__declspec(dllexport) void declDef(); +void declDef() {} + +// Export inline function. +__declspec(dllexport) inline void inlineFunc() {} + +__declspec(dllexport) inline void inlineDecl(); +void inlineDecl() {} + +__declspec(dllexport) void inlineDef(); +inline void inlineDef() {} + +// Export ignored for declarations. +__declspec(dllexport) void decl(); + +// Redeclarations +__declspec(dllexport) void redecl1(); +__declspec(dllexport) void redecl1(); + +__declspec(dllexport) void redecl2(); + void redecl2(); + +__declspec(dllexport) void redecl3(); + void redecl3() {} + + void redecl4(); // expected-note{{previous declaration is here}} +__declspec(dllexport) void redecl4(); // expected-error{{'redecl4' redeclared with different DLL attributes}} + + void redecl5(); // expected-note{{previous declaration is here}} +__declspec(dllexport) inline void redecl5() {} // expected-error{{'redecl5' redeclared with different DLL attributes}} + + +// Exported a function template. +template __declspec(dllexport) void exportedFuncTmpl() {} + +// Export specializations of an exported function template. +template<> __declspec(dllexport) void exportedFuncTmpl() {} +template<> __declspec(dllexport) inline void exportedFuncTmpl() {} + +// Not exporting specialization without explicit dllexport. +template<> void exportedFuncTmpl() {} + +// Exporting specializations of a non-exported function template. +template void funcTmpl() {} +template<> __declspec(dllexport) void funcTmpl() {} + + +// Ensure all function templates are instantiated. +template void exportedFuncTmpl(); +template void exportedFuncTmpl(); +template void exportedFuncTmpl(); +template void exportedFuncTmpl(); + +template void funcTmpl(); +template void funcTmpl(); + + + +// dllexport takes precedence over the dllimport if both are specified. +__attribute__((dllimport, dllexport)) extern int PrecedenceGlobal1A; // expected-warning{{dllimport attribute ignored}} +__declspec(dllimport) __declspec(dllexport) extern int PrecedenceGlobal1B; // expected-warning{{dllimport attribute ignored}} + +__attribute__((dllexport, dllimport)) extern int PrecedenceGlobal2A; // expected-warning{{dllimport attribute ignored}} +__declspec(dllexport) __declspec(dllimport) extern int PrecedenceGlobal2B; // expected-warning{{dllimport attribute ignored}} + +__declspec(dllexport) extern int PrecedenceGlobalRececl1; +__declspec(dllimport) extern int PrecedenceGlobalRececl1; // expected-warning{{dllimport attribute ignored}} + +__declspec(dllimport) extern int PrecedenceGlobalRedecl2; // expected-warning{{dllimport attribute ignored}} +__declspec(dllexport) extern int PrecedenceGlobalRedecl2; + +__attribute__((dllexport)) extern int PrecedenceGlobalMixed1; +__declspec(dllimport) extern int PrecedenceGlobalMixed1; // expected-warning{{dllimport attribute ignored}} + +__attribute__((dllimport)) extern int PrecedenceGlobalMixed2; // expected-warning{{dllimport attribute ignored}} +__declspec(dllexport) extern int PrecedenceGlobalMixed2; + +void __attribute__((dllimport, dllexport)) precedence1A(); // expected-warning{{dllimport attribute ignored}} +void __declspec(dllimport) __declspec(dllexport) precedence1B(); // expected-warning{{dllimport attribute ignored}} + +void __attribute__((dllexport, dllimport)) precedence2A(); // expected-warning{{dllimport attribute ignored}} +void __declspec(dllexport) __declspec(dllimport) precedence2B(); // expected-warning{{dllimport attribute ignored}} + +void __declspec(dllimport) precedenceRedecl1(); // expected-warning{{dllimport attribute ignored}} +void __declspec(dllexport) precedenceRedecl1(); + +void __declspec(dllexport) precedenceRedecl2(); +void __declspec(dllimport) precedenceRedecl2(); // expected-warning{{dllimport attribute ignored}} + + + +// Classes + +// Export the whole class. +struct __declspec(dllexport) ExportClass { + struct Nested1 { + void normal() {} + }; + struct __declspec(dllexport) Nested2 { + void normal(); + }; + struct Nested3 { + __declspec(dllexport) void normal(); + }; + struct __declspec(dllimport) Nested4 { + void normal(); + }; + struct Nested5 { + __declspec(dllimport) void normal(); + }; + +public: + void publicNormalDefined(); + void publicNormalInside() {} + void publicNormalInlineDef(); + inline void publicNormalInlineDecl(); + virtual void publicVirtualDefined(); + virtual void publicVirtualInside() {} + virtual void publicVirtualInlineDef(); + virtual inline void publicVirtualInlineDecl(); + static void publicStaticDefined(); + static void publicStaticInside() {} + static void publicStaticInlineDef(); + static inline void publicStaticInlineDecl(); + + int publicField; + static int publicStaticFieldDefined; + static const int publicStaticConstFieldDefined; + static const int publicStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int publicConstexprField = 2; +#endif + +protected: + void protectedNormalDefined(); + void protectedNormalInside() {} + void protectedNormalInlineDef(); + inline void protectedNormalInlineDecl(); + virtual void protectedVirtualDefined(); + virtual void protectedVirtualInside() {} + virtual void protectedVirtualInlineDef(); + virtual inline void protectedVirtualInlineDecl(); + static void protectedStaticDefined(); + static void protectedStaticInside() {} + static void protectedStaticInlineDef(); + static inline void protectedStaticInlineDecl(); + + int protectedField; + static int protectedStaticFieldDefined; + static const int protectedStaticConstFieldDefined; + static const int protectedStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int protectedConstexprField = 2; +#endif + +private: + void privateNormalDefined(); + void privateNormalInside() {} + void privateNormalInlineDef(); + inline void privateNormalInlineDecl(); + virtual void privateVirtualDefined(); + virtual void privateVirtualInside() {} + virtual void privateVirtualInlineDef(); + virtual inline void privateVirtualInlineDecl(); + static void privateStaticDefined(); + static void privateStaticInside() {} + static void privateStaticInlineDef(); + static inline void privateStaticInlineDecl(); + + int privateField; + static int privateStaticFieldDefined; + static const int privateStaticConstFieldDefined; + static const int privateStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int privateConstexprField = 2; +#endif +}; + + void ExportClass::publicNormalDefined() {} + void ExportClass::publicVirtualDefined() {} + void ExportClass::publicStaticDefined() {} +inline void ExportClass::publicNormalInlineDef() {} +inline void ExportClass::publicVirtualInlineDef() {} +inline void ExportClass::publicStaticInlineDef() {} + void ExportClass::publicNormalInlineDecl() {} + void ExportClass::publicVirtualInlineDecl() {} + void ExportClass::publicStaticInlineDecl() {} + int ExportClass::publicStaticFieldDefined = 1; + const int ExportClass::publicStaticConstFieldDefined = 1; + + void ExportClass::protectedNormalDefined() {} + void ExportClass::protectedVirtualDefined() {} + void ExportClass::protectedStaticDefined() {} +inline void ExportClass::protectedNormalInlineDef() {} +inline void ExportClass::protectedVirtualInlineDef() {} +inline void ExportClass::protectedStaticInlineDef() {} + void ExportClass::protectedNormalInlineDecl() {} + void ExportClass::protectedVirtualInlineDecl() {} + void ExportClass::protectedStaticInlineDecl() {} + int ExportClass::protectedStaticFieldDefined = 1; + const int ExportClass::protectedStaticConstFieldDefined = 1; + + void ExportClass::privateNormalDefined() {} + void ExportClass::privateVirtualDefined() {} + void ExportClass::privateStaticDefined() {} +inline void ExportClass::privateNormalInlineDef() {} +inline void ExportClass::privateVirtualInlineDef() {} +inline void ExportClass::privateStaticInlineDef() {} + void ExportClass::privateNormalInlineDecl() {} + void ExportClass::privateVirtualInlineDecl() {} + void ExportClass::privateStaticInlineDecl() {} + int ExportClass::privateStaticFieldDefined = 1; + const int ExportClass::privateStaticConstFieldDefined = 1; + + +// Export individual struct members. +struct ExportMembers { + __declspec(dllexport) void normal(); + __declspec(dllexport) void normalDefined(); + __declspec(dllexport) void normalInside() {} + __declspec(dllexport) void normalInlineDef(); + __declspec(dllexport) inline void normalInlineDecl(); + __declspec(dllexport) virtual void virtualFun(); + __declspec(dllexport) virtual void virtualDefined(); + __declspec(dllexport) virtual void virtualInside() {} + __declspec(dllexport) virtual void virtualInlineDef(); + __declspec(dllexport) virtual inline void virtualInlineDecl(); + __declspec(dllexport) static void staticFun(); + __declspec(dllexport) static void staticDefined(); + __declspec(dllexport) static void staticInside() {} + __declspec(dllexport) static void staticInlineDef(); + __declspec(dllexport) static inline void staticInlineDecl(); + + __declspec(dllexport) int field; // expected-error{{'dllexport' attribute only applies to variables, functions and tag types}} + __declspec(dllexport) static int staticFieldDefined; + __declspec(dllexport) static const int staticConstField = 1; + __declspec(dllexport) static const int staticConstFieldDefined; +#if __has_feature(cxx_constexpr) + __declspec(dllexport) constexpr static int constexprField = 2; +#endif + + void ignoredNormal(); + void ignoredImplicitInline() {} + virtual void ignoredVirtual(); + virtual void ignoredVirtualImplicitInline() {} + static int ignoredStaticField; +}; + + void ExportMembers::normalDefined() {} + void ExportMembers::virtualDefined() {} + void ExportMembers::staticDefined() {} +inline void ExportMembers::normalInlineDef() {} +inline void ExportMembers::virtualInlineDef() {} +inline void ExportMembers::staticInlineDef() {} + void ExportMembers::normalInlineDecl() {} + void ExportMembers::virtualInlineDecl() {} + void ExportMembers::staticInlineDecl() {} + int ExportMembers::staticFieldDefined = 1; + const int ExportMembers::staticConstFieldDefined = 1; + + +// If the whole class is exported, individual members cannot have an attribute. +struct __declspec(dllexport) ExportClassAndMembers { + __declspec(dllexport) void expNormal(); // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) void expImplicitInline() {} // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtual(); // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtualImplicitInline() {} // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStatic(); // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStaticImplicitInline() {} // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) static int expStaticField; // expected-error{{member of exported class may not be declared with dllexport attribute}} + + __declspec(dllimport) void impNormal(); // expected-error{{member of exported class may not be declared with dllimport attribute}} + __declspec(dllimport) virtual void impVirtual(); // expected-error{{member of exported class may not be declared with dllimport attribute}} + __declspec(dllimport) static void impStatic(); // expected-error{{member of exported class may not be declared with dllimport attribute}} + __declspec(dllimport) static int impStaticField; // expected-error{{member of exported class may not be declared with dllimport attribute}} +}; + +template +struct __declspec(dllexport) ExportClassAndMembersTmpl { + __declspec(dllexport) void expNormal(); // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) void expImplicitInline() {} // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtual(); // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtualImplicitInline() {} // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStatic(); // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStaticImplicitInline() {} // expected-error{{member of exported class may not be declared with dllexport attribute}} + __declspec(dllexport) static int expStaticField; // expected-error{{member of exported class may not be declared with dllexport attribute}} + + __declspec(dllimport) void impNormal(); // expected-error{{member of exported class may not be declared with dllimport attribute}} + __declspec(dllimport) virtual void impVirtual(); // expected-error{{member of exported class may not be declared with dllimport attribute}} + __declspec(dllimport) static void impStatic(); // expected-error{{member of exported class may not be declared with dllimport attribute}} + __declspec(dllimport) static int impStaticField; // expected-error{{member of exported class may not be declared with dllimport attribute}} +}; + + +// Warn about non-exported associated types, like base classes or field types. +struct __attribute__((dllimport)) Imported {}; +struct __attribute__((dllexport)) Exported {}; +struct NotImported {}; +struct NotExported {}; +struct NotExported2 {}; + +struct __declspec(dllexport) ExportAssociated + : public Exported + , public NotExported // expected-warning{{'NotExported' is a base of an exported type and should be exported}} + , public NotExported2 { // expected-warning{{'NotExported2' is a base of an exported type and should be exported}} + static Exported staticFieldExportedType; + Exported returnExported(); + NotExported m1(); // expected-warning{{'NotExported' is accessible from exported type and should be exported}} + void m2(NotExported); + void m3(NotExported&); + void m4(NotExported*); + NotExported& m5(); + NotExported* m6(); +}; + + +template +struct Base { + void B1() { } +}; + +template +struct __attribute__((dllexport)) ExportedBase { + void B2() { } +}; + +template +struct __attribute__((dllexport)) InstanciatedBase { + void B3() { } +}; + +struct __attribute__((dllexport)) Derived + : public Base, // expected-warning{{'Base' is a base of an exported type and should be exported}} + public ExportedBase, + public InstanciatedBase { + void D() { } +}; + +template struct Base; +template struct __attribute__((dllexport)) InstanciatedBase; Index: cfe/trunk/test/SemaCXX/dllimport.cpp =================================================================== --- /dev/null +++ cfe/trunk/test/SemaCXX/dllimport.cpp @@ -0,0 +1,528 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -x c++ -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i386-pc-win32 -x c++ -std=c++11 -fsyntax-only -verify %s +#if 1 +// Helper structs to make template specializations more expressive. +struct ImplicitInst_Imported {}; +struct ImplicitInst_NotImported {}; +struct ExplicitSpec_Imported {}; +struct ExplicitSpec_NotImported {}; +struct ExplicitSpec_Def_Imported {}; +struct ExplicitSpec_InlineDef_Imported {}; + + +// Invalid decls. +__declspec(dllimport) typedef int typedef1; // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllimport) int typedef2; // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} +typedef int __declspec(dllimport) typedef3; // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} +typedef __declspec(dllimport) void (*FunTy)(); // expected-warning{{'dllimport' attribute only applies to variables, functions and tag types}} + + + +// Globals + +// Import declarations. +__declspec(dllimport) int GlobalDecl; +__declspec(dllimport) extern int ExternGlobalDecl; + +// Not allowed on definitions. +__declspec(dllimport) int GlobalDef = 3; // expected-error{{'dllimport' attribute cannot be specified on a definition}} + +// Reject inconsistent redeclarations. +extern int GlobalRedecl1; // expected-note{{previous declaration is here}} +__declspec(dllimport) extern int GlobalRedecl1; // expected-error{{'GlobalRedecl1' redeclared with different DLL attributes}} + +// NB: MSVC issues a warning and makes GlobalRedecl2 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) extern int GlobalRedecl2; // expected-note{{previous attribute is here}} +extern int GlobalRedecl2; // expected-warning{{'GlobalRedecl2' redeclared without dllimport attribute: previous dllimport ignored}} + +// Extern linkage is required. +__declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage to be imported}} + +void functionScope() { + __declspec(dllimport) int LocalVar; + __declspec(dllimport) extern int ExternLocalVar; + __declspec(dllimport) static int StaticLocalVar; // expected-error{{'StaticLocalVar' must have external linkage to be imported}} +} + + + +// Functions + +// Import function declaration. +__attribute__((dllimport)) void declA(); // Sanity check with __attribute__ +__declspec(dllimport) void declB(); + +// Not allowed on function definitions. +__declspec(dllimport) void def() {} // expected-error{{'dllimport' attribute cannot be specified on a definition}} + +// Import inline function definition. +__declspec(dllimport) inline void inlineFunc() {} + +__declspec(dllimport) inline void inlineDecl(); +void inlineDecl() {} + +__declspec(dllimport) void inlineDef(); +inline void inlineDef() {} + +// Redeclarations +__declspec(dllimport) void redecl1(); +__declspec(dllimport) void redecl1(); + +// NB: MSVC issues a warning and makes redecl2/redecl3 dllexport. We follow GCC +// and drop the dllimport with a warning. +__declspec(dllimport) void redecl2(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + void redecl2(); // expected-warning{{'redecl2' redeclared without dllimport attribute: previous dllimport ignored}} + +__declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + void redecl3() {} // expected-warning{{'redecl3' redeclared without dllimport attribute: previous dllimport ignored}} + + void redecl4(); // expected-note{{previous declaration is here}} +__declspec(dllimport) void redecl4(); // expected-error{{'redecl4' redeclared with different DLL attributes}} + + void redecl5(); // expected-note{{previous declaration is here}} +__declspec(dllimport) inline void redecl5() {} // expected-error{{'redecl5' redeclared with different DLL attributes}} + + +// Imported function template. +template __declspec(dllimport) void importedFuncTmpl(); + +// Import specialization of a function template. +template<> __declspec(dllimport) void importedFuncTmpl(); +template<> __declspec(dllimport) void importedFuncTmpl() {} +template<> __declspec(dllimport) inline void importedFuncTmpl() {} + +// Not importing specialization without explicit dllimport. +template<> void importedFuncTmpl() {} + +// Importing specializations of a non-imported function template. +template void funcTmpl() {} +template<> __declspec(dllimport) void funcTmpl(); + + +// Ensure all functions are used. +void useFunctions() { + importedFuncTmpl(); + importedFuncTmpl(); + importedFuncTmpl(); + importedFuncTmpl(); + importedFuncTmpl(); + + funcTmpl(); + funcTmpl(); +} + + + +// Classes + +// Import whole class. +struct __declspec(dllimport) ImportClass { // expected-note 9 {{previous attribute is here}} + struct Nested1 { + void normal(); + }; + struct __declspec(dllexport) Nested2 { + void normal(); + }; + struct Nested3 { + __declspec(dllexport) void normal(); + }; + struct __declspec(dllimport) Nested4 { + void normal(); + }; + struct Nested5 { + __declspec(dllimport) void normal(); + }; + +#if __has_feature(cxx_defaulted_functions) + ImportClass() = default; +#endif +#if __has_feature(cxx_deleted_functions) + ImportClass(const ImportClass&) = delete; +#endif + +public: + void publicNormal(); + void publicNormalDefined(); // expected-note{{previous declaration is here}} + void publicNormalInside() {} + void publicNormalInlineDef(); + inline void publicNormalInlineDecl(); + virtual void publicVirtual(); + virtual void publicVirtualDefined(); // expected-note{{previous declaration is here}} + virtual void publicVirtualInside() {} + virtual void publicVirtualInlineDef(); + virtual inline void publicVirtualInlineDecl(); + static void publicStatic(); + static void publicStaticDefined(); // expected-note{{previous declaration is here}} + static void publicStaticInside() {} + static void publicStaticInlineDef(); + static inline void publicStaticInlineDecl(); + + int publicField; + static int publicStaticField; + static int publicStaticFieldDefined; + static const int publicStaticConstField; + static const int publicStaticConstFieldDefined; + static const int publicStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int publicConstexprField = 2; +#endif + +protected: + void protectedNormal(); + void protectedNormalDefined(); // expected-note{{previous declaration is here}} + void protectedNormalInside() {} + void protectedNormalInlineDef(); + inline void protectedNormalInlineDecl(); + virtual void protectedVirtual(); + virtual void protectedVirtualDefined(); // expected-note{{previous declaration is here}} + virtual void protectedVirtualInside() {} + virtual void protectedVirtualInlineDef(); + virtual inline void protectedVirtualInlineDecl(); + static void protectedStatic(); + static void protectedStaticDefined(); // expected-note{{previous declaration is here}} + static void protectedStaticInside() {} + static void protectedStaticInlineDef(); + static inline void protectedStaticInlineDecl(); + + int protectedField; + static int protectedStaticField; + static int protectedStaticFieldDefined; + static const int protectedStaticConstField; + static const int protectedStaticConstFieldDefined; + static const int protectedStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int protectedConstexprField = 2; +#endif + +private: + void privateNormal(); + void privateNormalDefined(); // expected-note{{previous declaration is here}} + void privateNormalInside() {} + void privateNormalInlineDef(); + inline void privateNormalInlineDecl(); + virtual void privateVirtual(); + virtual void privateVirtualDefined(); // expected-note{{previous declaration is here}} + virtual void privateVirtualInside() {} + virtual void privateVirtualInlineDef(); + virtual inline void privateVirtualInlineDecl(); + static void privateStatic(); + static void privateStaticDefined(); // expected-note{{previous declaration is here}} + static void privateStaticInside() {} + static void privateStaticInlineDef(); + static inline void privateStaticInlineDecl(); + + int privateField; + static int privateStaticField; + static int privateStaticFieldDefined; + static const int privateStaticConstField; + static const int privateStaticConstFieldDefined; + static const int privateStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int privateConstexprField = 2; +#endif +}; + + void ImportClass::publicNormalDefined() {} // expected-warning{{'ImportClass::publicNormalDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportClass::publicVirtualDefined() {} // expected-warning{{'ImportClass::publicVirtualDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportClass::publicStaticDefined() {} // expected-warning{{'ImportClass::publicStaticDefined' redeclared without dllimport attribute: previous dllimport ignored}} +inline void ImportClass::publicNormalInlineDef() {} +inline void ImportClass::publicVirtualInlineDef() {} +inline void ImportClass::publicStaticInlineDef() {} + void ImportClass::publicNormalInlineDecl() {} + void ImportClass::publicVirtualInlineDecl() {} + void ImportClass::publicStaticInlineDecl() {} + int ImportClass::publicStaticFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + const int ImportClass::publicStaticConstFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + + void ImportClass::protectedNormalDefined() {} // expected-warning{{'ImportClass::protectedNormalDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportClass::protectedVirtualDefined() {} // expected-warning{{'ImportClass::protectedVirtualDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportClass::protectedStaticDefined() {} // expected-warning{{'ImportClass::protectedStaticDefined' redeclared without dllimport attribute: previous dllimport ignored}} +inline void ImportClass::protectedNormalInlineDef() {} +inline void ImportClass::protectedVirtualInlineDef() {} +inline void ImportClass::protectedStaticInlineDef() {} + void ImportClass::protectedNormalInlineDecl() {} + void ImportClass::protectedVirtualInlineDecl() {} + void ImportClass::protectedStaticInlineDecl() {} + int ImportClass::protectedStaticFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + const int ImportClass::protectedStaticConstFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + + void ImportClass::privateNormalDefined() {} // expected-warning{{'ImportClass::privateNormalDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportClass::privateVirtualDefined() {} // expected-warning{{'ImportClass::privateVirtualDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportClass::privateStaticDefined() {} // expected-warning{{'ImportClass::privateStaticDefined' redeclared without dllimport attribute: previous dllimport ignored}} +inline void ImportClass::privateNormalInlineDef() {} +inline void ImportClass::privateVirtualInlineDef() {} +inline void ImportClass::privateStaticInlineDef() {} + void ImportClass::privateNormalInlineDecl() {} + void ImportClass::privateVirtualInlineDecl() {} + void ImportClass::privateStaticInlineDecl() {} + int ImportClass::privateStaticFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + const int ImportClass::privateStaticConstFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + + +// Import individual members. +struct ImportMembers { +#if __has_feature(cxx_defaulted_functions) + __declspec(dllimport) ImportMembers() = default; +#endif +#if __has_feature(cxx_deleted_functions) + __declspec(dllimport) ImportMembers(const ImportMembers&) = delete; +#endif + + __declspec(dllimport) void normal(); + __declspec(dllimport) void normalDefined(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) void normalInside() {} + __declspec(dllimport) void normalInlineDef(); + __declspec(dllimport) inline void normalInlineDecl(); + __declspec(dllimport) virtual void virtualFun(); + __declspec(dllimport) virtual void virtualDefined(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) virtual void virtualInside() {} + __declspec(dllimport) virtual void virtualInlineDef(); + __declspec(dllimport) virtual inline void virtualInlineDecl(); + __declspec(dllimport) static void staticFun(); + __declspec(dllimport) static void staticDefined(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) static void staticInside() {} + __declspec(dllimport) static void staticInlineDef(); + __declspec(dllimport) static inline void staticInlineDecl(); + + __declspec(dllimport) int field; // expected-error{{'dllimport' attribute only applies to variables, functions and tag types}} + __declspec(dllimport) static int staticField; + __declspec(dllimport) static int staticFieldDefined; + __declspec(dllimport) static const int staticConstField; + __declspec(dllimport) static const int staticConstFieldDefined; + __declspec(dllimport) static const int staticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + __declspec(dllimport) constexpr static int constexprField = 2; +#endif + + void ignoredNormal(); + void ignoredInside() {} + virtual void ignoredVirtual(); + virtual void ignoredVirtualInside() {} + static int ignoredStaticField; +}; + + void ImportMembers::normalDefined() {} // expected-warning{{'ImportMembers::normalDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportMembers::virtualDefined() {} // expected-warning{{'ImportMembers::virtualDefined' redeclared without dllimport attribute: previous dllimport ignored}} + void ImportMembers::staticDefined() {} // expected-warning{{'ImportMembers::staticDefined' redeclared without dllimport attribute: previous dllimport ignored}} +inline void ImportMembers::normalInlineDef() {} +inline void ImportMembers::virtualInlineDef() {} +inline void ImportMembers::staticInlineDef() {} + void ImportMembers::normalInlineDecl() {} + void ImportMembers::virtualInlineDecl() {} + void ImportMembers::staticInlineDecl() {} + int ImportMembers::staticFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + const int ImportMembers::staticConstFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + + +// If the whole class is imported, individual members cannot have an attribute. +struct __declspec(dllimport) ImportClassAndMembers { + __declspec(dllexport) void expNormal(); // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) void expInside() {} // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtual(); // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtualInside() {} // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStatic(); // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStaticInside() {} // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) static int expStaticField; // expected-error{{member of imported class may not be declared with dllexport attribute}} + + __declspec(dllimport) void impNormal(); // expected-error{{member of imported class may not be declared with dllimport attribute}} + __declspec(dllimport) virtual void impVirtual(); // expected-error{{member of imported class may not be declared with dllimport attribute}} + __declspec(dllimport) static void impStatic(); // expected-error{{member of imported class may not be declared with dllimport attribute}} + __declspec(dllimport) static int impStaticField; // expected-error{{member of imported class may not be declared with dllimport attribute}} +}; + + +// Reject invalid redeclarations. +struct Redecls { + void normal(); // expected-note{{previous declaration is here}} + void inlineDef(); // expected-note{{previous declaration is here}} + inline void inlineDecl(); // expected-note{{previous declaration is here}} +}; +__declspec(dllimport) void Redecls::normal() {} // expected-error{{'normal' redeclared with different DLL attributes}} expected-error{{'dllimport' attribute cannot be specified on a definition}} +__declspec(dllimport) inline void Redecls::inlineDef() {} // expected-error{{'inlineDef' redeclared with different DLL attributes}} +__declspec(dllimport) void Redecls::inlineDecl() {} // expected-error{{'inlineDecl' redeclared with different DLL attributes}} + + + +// Class templates + +// Import whole class template. +template +struct __declspec(dllimport) ImportClassTmpl { // expected-note 3 {{previous attribute is here}} + void publicNormal(); + void publicNormalDefined(); // expected-note{{previous declaration is here}} + void publicNormalInside() {} + void publicNormalInlineDef(); + inline void publicNormalInlineDecl(); + virtual void publicVirtual(); + virtual void publicVirtualDefined(); // expected-note{{previous declaration is here}} + virtual void publicVirtualInside() {} + virtual void publicVirtualInlineDef(); + virtual inline void publicVirtualInlineDecl(); + static void publicStatic(); + static void publicStaticDefined(); // expected-note{{previous declaration is here}} + static void publicStaticInside() {} + static void publicStaticInlineDef(); + static inline void publicStaticInlineDecl(); + + int publicField; + static int publicStaticField; + static int publicStaticFieldDefined; + static const int publicStaticConstField; + static const int publicStaticConstFieldDefined; + static const int publicStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int publicConstexprField = 2; +#endif +}; + +// NB: MSVC is inconsistent here and disallows *InlineDef on class templates, +// but allows it on classes. We allow both. +template void ImportClassTmpl::publicNormalDefined() {} // expected-warning{{'ImportClassTmpl::publicNormalDefined' redeclared without dllimport attribute: previous dllimport ignored}} +template void ImportClassTmpl::publicVirtualDefined() {} // expected-warning{{'ImportClassTmpl::publicVirtualDefined' redeclared without dllimport attribute: previous dllimport ignored}} +template void ImportClassTmpl::publicStaticDefined() {} // expected-warning{{'ImportClassTmpl::publicStaticDefined' redeclared without dllimport attribute: previous dllimport ignored}} +template inline void ImportClassTmpl::publicNormalInlineDef() {} +template inline void ImportClassTmpl::publicVirtualInlineDef() {} +template inline void ImportClassTmpl::publicStaticInlineDef() {} +template void ImportClassTmpl::publicNormalInlineDecl() {} +template void ImportClassTmpl::publicVirtualInlineDecl() {} +template void ImportClassTmpl::publicStaticInlineDecl() {} +template int ImportClassTmpl::publicStaticFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} +template const int ImportClassTmpl::publicStaticConstFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + + + +template +struct ClassTmpl { + void publicNormal(); + void publicNormalDefined(); + void publicNormalInside() {} + void publicNormalInlineDef(); + inline void publicNormalInlineDecl(); + virtual void publicVirtual(); + virtual void publicVirtualDefined(); + virtual void publicVirtualInside() {} + virtual void publicVirtualInlineDef(); + virtual inline void publicVirtualInlineDecl(); + static void publicStatic(); + static void publicStaticDefined(); + static void publicStaticInside() {} + static void publicStaticInlineDef(); + static inline void publicStaticInlineDecl(); + + int publicField; + static int publicStaticField; + static int publicStaticFieldDefined; + static const int publicStaticConstField; + static const int publicStaticConstFieldDefined; + static const int publicStaticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + constexpr static int publicConstexprField = 2; +#endif +}; + +// NB: We follow MSVC here and ignore all illegal definitions when explicitly +// importing an explicit instantiation. +template void ClassTmpl::publicNormalDefined() {} +template void ClassTmpl::publicVirtualDefined() {} +template void ClassTmpl::publicStaticDefined() {} +template inline void ClassTmpl::publicNormalInlineDef() {} +template inline void ClassTmpl::publicVirtualInlineDef() {} +template inline void ClassTmpl::publicStaticInlineDef() {} +template void ClassTmpl::publicNormalInlineDecl() {} +template void ClassTmpl::publicVirtualInlineDecl() {} +template void ClassTmpl::publicStaticInlineDecl() {} +template int ClassTmpl::publicStaticFieldDefined = 1; +template const int ClassTmpl::publicStaticConstFieldDefined = 1; + +template struct __declspec(dllimport) ClassTmpl; + + +// Import individual members. +template +struct ImportMembersTmpl { + __declspec(dllimport) void normal(); + __declspec(dllimport) void normalDefined(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) void normalInside() {} + __declspec(dllimport) void normalInlineDef(); + __declspec(dllimport) inline void normalInlineDecl(); + __declspec(dllimport) virtual void virtualFun(); + __declspec(dllimport) virtual void virtualDefined(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) virtual void virtualInside() {} + __declspec(dllimport) virtual void virtualInlineDef(); + __declspec(dllimport) virtual inline void virtualInlineDecl(); + __declspec(dllimport) static void staticFun(); + __declspec(dllimport) static void staticDefined(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} + __declspec(dllimport) static void staticInside() {} + __declspec(dllimport) static void staticInlineDef(); + __declspec(dllimport) static inline void staticInlineDecl(); + + __declspec(dllimport) int field; // expected-error{{'dllimport' attribute only applies to variables, functions and tag types}} + __declspec(dllimport) static int staticField; + __declspec(dllimport) static int staticFieldDefined; + __declspec(dllimport) static const int staticConstField; + __declspec(dllimport) static const int staticConstFieldDefined; + __declspec(dllimport) static const int staticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + __declspec(dllimport) constexpr static int constexprField = 2; +#endif + + void ignoredNormal(); + void ignoredInside() {} + virtual void ignoredVirtual(); + virtual void ignoredVirtualInside() {} + static int ignoredStaticField; +}; + +// NB: MSVC is inconsistent here and disallows *InlineDef on class templates, +// but allows it on classes. We allow both. +template void ImportMembersTmpl::normalDefined() {} // expected-warning{{'ImportMembersTmpl::normalDefined' redeclared without dllimport attribute: previous dllimport ignored}} +template void ImportMembersTmpl::virtualDefined() {} // expected-warning{{'ImportMembersTmpl::virtualDefined' redeclared without dllimport attribute: previous dllimport ignored}} +template void ImportMembersTmpl::staticDefined() {} // expected-warning{{'ImportMembersTmpl::staticDefined' redeclared without dllimport attribute: previous dllimport ignored}} +template inline void ImportMembersTmpl::normalInlineDef() {} +template inline void ImportMembersTmpl::virtualInlineDef() {} +template inline void ImportMembersTmpl::staticInlineDef() {} +template void ImportMembersTmpl::normalInlineDecl() {} +template void ImportMembersTmpl::virtualInlineDecl() {} +template void ImportMembersTmpl::staticInlineDecl() {} +template int ImportMembersTmpl::staticFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} +template const int ImportMembersTmpl::staticConstFieldDefined = 1; // expected-error{{definition of 'dllimport' static field not allowed}} + + +// If the whole class is imported, individual members cannot have an attribute. +template +struct __declspec(dllimport) ImportClassAndMembersTmpl { + __declspec(dllexport) void expNormal(); // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) void expInside() {} // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtual(); // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) virtual void expVirtualInside() {} // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStatic(); // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) static void expStaticInside() {} // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) static int expStaticField; // expected-error{{member of imported class may not be declared with dllexport attribute}} + __declspec(dllexport) static const int expStaticConstField; // expected-error{{member of imported class may not be declared with dllexport attribute}} +#if __has_feature(cxx_constexpr) + __declspec(dllexport) constexpr static int expConstexprField = 2; // expected-error{{member of imported class may not be declared with dllexport attribute}} +#endif + + __declspec(dllimport) void impNormal(); // expected-error{{member of imported class may not be declared with dllimport attribute}} + __declspec(dllimport) virtual void impVirtual(); // expected-error{{member of imported class may not be declared with dllimport attribute}} + __declspec(dllimport) static void impStatic(); // expected-error{{member of imported class may not be declared with dllimport attribute}} + __declspec(dllimport) static int impStaticField; // expected-error{{member of imported class may not be declared with dllimport attribute}} + __declspec(dllimport) static const int impStaticConstField; // expected-error{{member of imported class may not be declared with dllimport attribute}} +#if __has_feature(cxx_constexpr) + __declspec(dllimport) constexpr static int impConstexprField = 2; // expected-error{{member of imported class may not be declared with dllimport attribute}} +#endif +}; + + +// Reject invalid redeclarations. +template +struct RedeclsTmpl { + void normal(); // expected-note{{previous declaration is here}} + void inlineDef(); // expected-note{{previous declaration is here}} + inline void inlineDecl(); // expected-note{{previous declaration is here}} +}; +template__declspec(dllimport) void RedeclsTmpl::normal() {} // expected-error{{'normal' redeclared with different DLL attributes}} expected-error{{'dllimport' attribute cannot be specified on a definition}} +template__declspec(dllimport) inline void RedeclsTmpl::inlineDef() {} // expected-error{{'inlineDef' redeclared with different DLL attributes}} +template__declspec(dllimport) void RedeclsTmpl::inlineDecl() {} // expected-error{{'inlineDecl' redeclared with different DLL attributes}} +#endif Index: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp +++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp @@ -1335,6 +1335,7 @@ << " default:\n" << " break;\n"; + Record *InhClass = Records.getClass("InheritableAttr"); for (std::vector::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { Record &R = **I; @@ -1355,7 +1356,13 @@ bool TDependent = R.getValueAsBit("TemplateDependent"); if (!TDependent) { - OS << " return A->clone(C);\n"; + if (R.isSubClassOf(InhClass)) { + OS << " InheritableAttr* CA = A->clone(C);\n"; + OS << " if (CA) CA->setInherited(A->isInherited());\n"; + OS << " return CA;\n"; + } else { + OS << " return A->clone(C);\n"; + } OS << " }\n"; continue; } Index: llvm/trunk/include/llvm-c/Core.h =================================================================== --- llvm/trunk/include/llvm-c/Core.h +++ llvm/trunk/include/llvm-c/Core.h @@ -281,8 +281,6 @@ LLVMInternalLinkage, /**< Rename collisions when linking (static functions) */ LLVMPrivateLinkage, /**< Like Internal, but omit from symbol table */ - LLVMDLLImportLinkage, /**< Function to be imported from DLL */ - LLVMDLLExportLinkage, /**< Function to be accessible from DLL */ LLVMExternalWeakLinkage,/**< ExternalWeak linkage description */ LLVMGhostLinkage, /**< Obsolete */ LLVMCommonLinkage, /**< Tentative definitions */ Index: llvm/trunk/include/llvm/IR/Attributes.h =================================================================== --- llvm/trunk/include/llvm/IR/Attributes.h +++ llvm/trunk/include/llvm/IR/Attributes.h @@ -71,6 +71,8 @@ ///< nobuiltin attribute on its declaration. ByVal, ///< Pass structure by value Cold, ///< Marks function as being in a cold path. + DLLExport, ///< Export this function from DLL + DLLImport, ///< Import this function from DLL InlineHint, ///< Source said inlining was desirable InReg, ///< Force argument to be passed in register MinSize, ///< Function must be optimized for size first Index: llvm/trunk/include/llvm/IR/GlobalValue.h =================================================================== --- llvm/trunk/include/llvm/IR/GlobalValue.h +++ llvm/trunk/include/llvm/IR/GlobalValue.h @@ -43,8 +43,6 @@ PrivateLinkage, ///< Like Internal, but omit from symbol table. LinkerPrivateLinkage, ///< Like Private, but linker removes. LinkerPrivateWeakLinkage, ///< Like LinkerPrivate, but weak. - DLLImportLinkage, ///< Function to be imported from DLL - DLLExportLinkage, ///< Function to be accessible from DLL. ExternalWeakLinkage,///< ExternalWeak linkage description. CommonLinkage ///< Tentative definitions. }; @@ -92,7 +90,7 @@ return Visibility == ProtectedVisibility; } void setVisibility(VisibilityTypes V) { Visibility = V; } - + bool hasSection() const { return !Section.empty(); } const std::string &getSection() const { return Section; } void setSection(StringRef S) { Section = S; } @@ -152,12 +150,6 @@ return isInternalLinkage(Linkage) || isPrivateLinkage(Linkage) || isLinkerPrivateLinkage(Linkage) || isLinkerPrivateWeakLinkage(Linkage); } - static bool isDLLImportLinkage(LinkageTypes Linkage) { - return Linkage == DLLImportLinkage; - } - static bool isDLLExportLinkage(LinkageTypes Linkage) { - return Linkage == DLLExportLinkage; - } static bool isExternalWeakLinkage(LinkageTypes Linkage) { return Linkage == ExternalWeakLinkage; } @@ -219,8 +211,6 @@ return isLinkerPrivateWeakLinkage(Linkage); } bool hasLocalLinkage() const { return isLocalLinkage(Linkage); } - bool hasDLLImportLinkage() const { return isDLLImportLinkage(Linkage); } - bool hasDLLExportLinkage() const { return isDLLExportLinkage(Linkage); } bool hasExternalWeakLinkage() const { return isExternalWeakLinkage(Linkage); } bool hasCommonLinkage() const { return isCommonLinkage(Linkage); } Index: llvm/trunk/include/llvm/IR/GlobalVariable.h =================================================================== --- llvm/trunk/include/llvm/IR/GlobalVariable.h +++ llvm/trunk/include/llvm/IR/GlobalVariable.h @@ -48,6 +48,7 @@ // can change from its initial // value before global // initializers are run? + unsigned dllStorageClass : 2; // DLL storage class public: // allocate space for exactly one operand @@ -63,6 +64,13 @@ LocalExecTLSModel }; + /// @brief Storage classes of global values for PE targets. + enum DLLStorageClassTypes { + DefaultStorageClass = 0, + DLLImportStorageClass = 1, ///< Function to be imported from DLL + DLLExportStorageClass = 2 ///< Function to be accessible from DLL. + }; + /// GlobalVariable ctor - If a parent module is specified, the global is /// automatically inserted into the end of the specified modules global list. GlobalVariable(Type *Ty, bool isConstant, LinkageTypes Linkage, @@ -167,6 +175,17 @@ return static_cast(threadLocalMode); } + DLLStorageClassTypes getDLLStorageClass() const { + return DLLStorageClassTypes(dllStorageClass); + } + bool hasDLLImportStorageClass() const { + return dllStorageClass == DLLImportStorageClass; + } + bool hasDLLExportStorageClass() const { + return dllStorageClass == DLLExportStorageClass; + } + void setDLLStorageClass(DLLStorageClassTypes C) { dllStorageClass = C; } + bool isExternallyInitialized() const { return isExternallyInitializedConstant; } Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -250,9 +250,7 @@ case lltok::kw_linkonce_odr: // OptionalLinkage case lltok::kw_linkonce_odr_auto_hide: // OptionalLinkage case lltok::kw_appending: // OptionalLinkage - case lltok::kw_dllexport: // OptionalLinkage case lltok::kw_common: // OptionalLinkage - case lltok::kw_dllimport: // OptionalLinkage case lltok::kw_extern_weak: // OptionalLinkage case lltok::kw_external: { // OptionalLinkage unsigned Linkage, Visibility; @@ -725,8 +723,7 @@ // If the linkage is specified and is external, then no initializer is // present. Constant *Init = 0; - if (!HasLinkage || (Linkage != GlobalValue::DLLImportLinkage && - Linkage != GlobalValue::ExternalWeakLinkage && + if (!HasLinkage || (Linkage != GlobalValue::ExternalWeakLinkage && Linkage != GlobalValue::ExternalLinkage)) { if (ParseGlobalValue(Ty, Init)) return true; @@ -792,6 +789,12 @@ unsigned Alignment; if (ParseOptionalAlignment(Alignment)) return true; GV->setAlignment(Alignment); + } else if (Lex.getKind() == lltok::kw_dllimport) { + Lex.Lex(); + GV->setDLLStorageClass(GlobalVariable::DLLImportStorageClass); + } else if (Lex.getKind() == lltok::kw_dllexport) { + Lex.Lex(); + GV->setDLLStorageClass(GlobalVariable::DLLExportStorageClass); } else { TokError("unknown global variable property!"); } @@ -911,6 +914,8 @@ case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break; case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break; case lltok::kw_cold: B.addAttribute(Attribute::Cold); break; + case lltok::kw_dllexport: B.addAttribute(Attribute::DLLExport); break; + case lltok::kw_dllimport: B.addAttribute(Attribute::DLLImport); break; case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break; case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break; case lltok::kw_naked: B.addAttribute(Attribute::Naked); break; @@ -1270,9 +1275,7 @@ /// ::= 'linkonce_odr_auto_hide' /// ::= 'available_externally' /// ::= 'appending' -/// ::= 'dllexport' /// ::= 'common' -/// ::= 'dllimport' /// ::= 'extern_weak' /// ::= 'external' bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage) { @@ -1297,9 +1300,7 @@ Res = GlobalValue::AvailableExternallyLinkage; break; case lltok::kw_appending: Res = GlobalValue::AppendingLinkage; break; - case lltok::kw_dllexport: Res = GlobalValue::DLLExportLinkage; break; case lltok::kw_common: Res = GlobalValue::CommonLinkage; break; - case lltok::kw_dllimport: Res = GlobalValue::DLLImportLinkage; break; case lltok::kw_extern_weak: Res = GlobalValue::ExternalWeakLinkage; break; case lltok::kw_external: Res = GlobalValue::ExternalLinkage; break; } @@ -2935,7 +2936,6 @@ switch ((GlobalValue::LinkageTypes)Linkage) { case GlobalValue::ExternalLinkage: break; // always ok. - case GlobalValue::DLLImportLinkage: case GlobalValue::ExternalWeakLinkage: if (isDefine) return Error(LinkageLoc, "invalid linkage for function definition"); @@ -2950,7 +2950,6 @@ case GlobalValue::LinkOnceODRAutoHideLinkage: case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: - case GlobalValue::DLLExportLinkage: if (!isDefine) return Error(LinkageLoc, "invalid linkage for function declaration"); break; Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -77,8 +77,6 @@ case 2: return GlobalValue::AppendingLinkage; case 3: return GlobalValue::InternalLinkage; case 4: return GlobalValue::LinkOnceAnyLinkage; - case 5: return GlobalValue::DLLImportLinkage; - case 6: return GlobalValue::DLLExportLinkage; case 7: return GlobalValue::ExternalWeakLinkage; case 8: return GlobalValue::CommonLinkage; case 9: return GlobalValue::PrivateLinkage; Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -397,8 +397,6 @@ case GlobalValue::AppendingLinkage: return 2; case GlobalValue::InternalLinkage: return 3; case GlobalValue::LinkOnceAnyLinkage: return 4; - case GlobalValue::DLLImportLinkage: return 5; - case GlobalValue::DLLExportLinkage: return 6; case GlobalValue::ExternalWeakLinkage: return 7; case GlobalValue::CommonLinkage: return 8; case GlobalValue::PrivateLinkage: return 9; Index: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -240,7 +240,6 @@ OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak); } break; - case GlobalValue::DLLExportLinkage: case GlobalValue::AppendingLinkage: // FIXME: appending linkage variables should go into a section of // their name or something. For now, just emit them as external. Index: llvm/trunk/lib/ExecutionEngine/ExecutionEngine.cpp =================================================================== --- llvm/trunk/lib/ExecutionEngine/ExecutionEngine.cpp +++ llvm/trunk/lib/ExecutionEngine/ExecutionEngine.cpp @@ -1199,9 +1199,7 @@ } // If the existing global is strong, never replace it. - if (GVEntry->hasExternalLinkage() || - GVEntry->hasDLLImportLinkage() || - GVEntry->hasDLLExportLinkage()) + if (GVEntry->hasExternalLinkage()) continue; // Otherwise, we know it's linkonce/weak, replace it if this is a strong Index: llvm/trunk/lib/IR/AsmWriter.cpp =================================================================== --- llvm/trunk/lib/IR/AsmWriter.cpp +++ llvm/trunk/lib/IR/AsmWriter.cpp @@ -1399,8 +1399,6 @@ case GlobalValue::WeakODRLinkage: Out << "weak_odr "; break; case GlobalValue::CommonLinkage: Out << "common "; break; case GlobalValue::AppendingLinkage: Out << "appending "; break; - case GlobalValue::DLLImportLinkage: Out << "dllimport "; break; - case GlobalValue::DLLExportLinkage: Out << "dllexport "; break; case GlobalValue::ExternalWeakLinkage: Out << "extern_weak "; break; case GlobalValue::AvailableExternallyLinkage: Out << "available_externally "; @@ -1472,6 +1470,12 @@ if (GV->getAlignment()) Out << ", align " << GV->getAlignment(); + switch (GV->getDLLStorageClass()) { + case GlobalVariable::DefaultStorageClass: break; + case GlobalVariable::DLLImportStorageClass: Out << ", dllimport"; break; + case GlobalVariable::DLLExportStorageClass: Out << ", dllexport"; break; + } + printInfoComment(*GV); } Index: llvm/trunk/lib/IR/Attributes.cpp =================================================================== --- llvm/trunk/lib/IR/Attributes.cpp +++ llvm/trunk/lib/IR/Attributes.cpp @@ -161,6 +161,10 @@ return "builtin"; if (hasAttribute(Attribute::ByVal)) return "byval"; + if (hasAttribute(Attribute::DLLExport)) + return "dllexport"; + if (hasAttribute(Attribute::DLLImport)) + return "dllimport"; if (hasAttribute(Attribute::InlineHint)) return "inlinehint"; if (hasAttribute(Attribute::InReg)) @@ -402,6 +406,8 @@ case Attribute::Returned: return 1ULL << 39; case Attribute::Cold: return 1ULL << 40; case Attribute::Builtin: return 1ULL << 41; + case Attribute::DLLExport: return 1ULL << 42; + case Attribute::DLLImport: return 1ULL << 43; } llvm_unreachable("Unsupported attribute type"); } Index: llvm/trunk/lib/IR/Core.cpp =================================================================== --- llvm/trunk/lib/IR/Core.cpp +++ llvm/trunk/lib/IR/Core.cpp @@ -1126,10 +1126,6 @@ return LLVMLinkerPrivateLinkage; case GlobalValue::LinkerPrivateWeakLinkage: return LLVMLinkerPrivateWeakLinkage; - case GlobalValue::DLLImportLinkage: - return LLVMDLLImportLinkage; - case GlobalValue::DLLExportLinkage: - return LLVMDLLExportLinkage; case GlobalValue::ExternalWeakLinkage: return LLVMExternalWeakLinkage; case GlobalValue::CommonLinkage: @@ -1179,12 +1175,6 @@ case LLVMLinkerPrivateWeakLinkage: GV->setLinkage(GlobalValue::LinkerPrivateWeakLinkage); break; - case LLVMDLLImportLinkage: - GV->setLinkage(GlobalValue::DLLImportLinkage); - break; - case LLVMDLLExportLinkage: - GV->setLinkage(GlobalValue::DLLExportLinkage); - break; case LLVMExternalWeakLinkage: GV->setLinkage(GlobalValue::ExternalWeakLinkage); break; Index: llvm/trunk/lib/IR/Globals.cpp =================================================================== --- llvm/trunk/lib/IR/Globals.cpp +++ llvm/trunk/lib/IR/Globals.cpp @@ -91,7 +91,8 @@ OperandTraits::op_begin(this), InitVal != 0, Link, Name), isConstantGlobal(constant), threadLocalMode(TLMode), - isExternallyInitializedConstant(isExternallyInitialized) { + isExternallyInitializedConstant(isExternallyInitialized), + dllStorageClass(DefaultStorageClass) { if (InitVal) { assert(InitVal->getType() == Ty && "Initializer should be the same type as the GlobalVariable!"); @@ -112,7 +113,8 @@ OperandTraits::op_begin(this), InitVal != 0, Link, Name), isConstantGlobal(constant), threadLocalMode(TLMode), - isExternallyInitializedConstant(isExternallyInitialized) { + isExternallyInitializedConstant(isExternallyInitialized), + dllStorageClass(DefaultStorageClass) { if (InitVal) { assert(InitVal->getType() == Ty && "Initializer should be the same type as the GlobalVariable!"); Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -388,16 +388,12 @@ Assert1(!GV.isDeclaration() || GV.isMaterializable() || GV.hasExternalLinkage() || - GV.hasDLLImportLinkage() || GV.hasExternalWeakLinkage() || (isa(GV) && (GV.hasLocalLinkage() || GV.hasWeakLinkage())), - "Global is external, but doesn't have external or dllimport or weak linkage!", + "Global is external, but doesn't have external or weak linkage!", &GV); - Assert1(!GV.hasDLLImportLinkage() || GV.isDeclaration(), - "Global is marked as dllimport, but not external", &GV); - Assert1(!GV.hasAppendingLinkage() || isa(GV), "Only global variables can have appending linkage!", &GV); @@ -427,8 +423,7 @@ &GV); } } else { - Assert1(GV.hasExternalLinkage() || GV.hasDLLImportLinkage() || - GV.hasExternalWeakLinkage(), + Assert1(GV.hasExternalLinkage() || GV.hasExternalWeakLinkage(), "invalid linkage type for global declaration", &GV); } @@ -473,6 +468,11 @@ } } + Assert1(!GV.hasDLLImportStorageClass() || GV.isDeclaration() || + GV.getLinkage() == GlobalValue::ExternalLinkage || + GV.getLinkage() == GlobalValue::AvailableExternallyLinkage, + "Global is marked as dllimport, but not external", &GV); + visitGlobalValue(GV); } @@ -694,7 +694,9 @@ I->getKindAsEnum() == Attribute::NoDuplicate || I->getKindAsEnum() == Attribute::Builtin || I->getKindAsEnum() == Attribute::NoBuiltin || - I->getKindAsEnum() == Attribute::Cold) { + I->getKindAsEnum() == Attribute::Cold || + I->getKindAsEnum() == Attribute::DLLImport || + I->getKindAsEnum() == Attribute::DLLExport) { if (!isFunction) { CheckFailed("Attribute '" + I->getAsString() + "' only applies to functions!", V); @@ -833,6 +835,12 @@ Attrs.hasAttribute(AttributeSet::FunctionIndex, Attribute::AlwaysInline)), "Attributes 'noinline and alwaysinline' are incompatible!", V); + + Assert1(!(Attrs.hasAttribute(AttributeSet::FunctionIndex, + Attribute::DLLImport) && + Attrs.hasAttribute(AttributeSet::FunctionIndex, + Attribute::DLLExport)), + "Attributes 'dllimport and dllexport' are incompatible!", V); } bool Verifier::VerifyAttributeCount(AttributeSet Attrs, unsigned Params) { @@ -924,8 +932,7 @@ if (F.isMaterializable()) { // Function has a body somewhere we can't see. } else if (F.isDeclaration()) { - Assert1(F.hasExternalLinkage() || F.hasDLLImportLinkage() || - F.hasExternalWeakLinkage(), + Assert1(F.hasExternalLinkage() || F.hasExternalWeakLinkage(), "invalid linkage type for function declaration", &F); } else { // Verify that this function (which has a body) is not named "llvm.*". It @@ -951,6 +958,10 @@ if (F.hasAddressTaken(&U)) Assert1(0, "Invalid user of intrinsic instruction!", U); } + + Assert1(!F.hasFnAttribute(Attribute::DLLImport) || F.isDeclaration() || + F.getLinkage() == GlobalValue::AvailableExternallyLinkage, + "Function is marked as dllimport, but not external.", &F); } // verifyBasicBlock - Verify that a basic block is well formed... Index: llvm/trunk/lib/Linker/LinkModules.cpp =================================================================== --- llvm/trunk/lib/Linker/LinkModules.cpp +++ llvm/trunk/lib/Linker/LinkModules.cpp @@ -509,6 +509,16 @@ return false; } +static bool hasDLLImport(const GlobalValue *G) { + if (const GlobalVariable *GV = dyn_cast(G)) + return GV->hasDLLImportStorageClass(); + + if (const Function *F = dyn_cast(G)) + return F->hasFnAttribute(Attribute::DLLImport); + + return false; +} + Value *ValueMaterializerTy::materializeValueFor(Value *V) { Function *SF = dyn_cast(V); if (!SF) @@ -538,12 +548,12 @@ bool SrcIsDeclaration = Src->isDeclaration() && !Src->isMaterializable(); bool DestIsDeclaration = Dest->isDeclaration(); - + if (SrcIsDeclaration) { // If Src is external or if both Src & Dest are external.. Just link the // external globals, we aren't adding anything. - if (Src->hasDLLImportLinkage()) { - // If one of GVs has DLLImport linkage, result should be dllimport'ed. + if (hasDLLImport(Src)) { + // If one of GVs is marked as DLLImport, result should be dllimport'ed. if (DestIsDeclaration) { LinkFromSrc = true; LT = Src->getLinkage(); @@ -556,7 +566,7 @@ LinkFromSrc = false; LT = Dest->getLinkage(); } - } else if (DestIsDeclaration && !Dest->hasDLLImportLinkage()) { + } else if (DestIsDeclaration && !hasDLLImport(Dest)) { // If Dest is external but Src is not: LinkFromSrc = true; LT = Src->getLinkage(); @@ -583,10 +593,8 @@ LT = GlobalValue::ExternalLinkage; } } else { - assert((Dest->hasExternalLinkage() || Dest->hasDLLImportLinkage() || - Dest->hasDLLExportLinkage() || Dest->hasExternalWeakLinkage()) && - (Src->hasExternalLinkage() || Src->hasDLLImportLinkage() || - Src->hasDLLExportLinkage() || Src->hasExternalWeakLinkage()) && + assert((Dest->hasExternalLinkage() || Dest->hasExternalWeakLinkage()) && + (Src->hasExternalLinkage() || Src->hasExternalWeakLinkage()) && "Unexpected linkage type!"); return emitError("Linking globals named '" + Src->getName() + "': symbol multiply defined!"); Index: llvm/trunk/lib/Target/CppBackend/CPPBackend.cpp =================================================================== --- llvm/trunk/lib/Target/CppBackend/CPPBackend.cpp +++ llvm/trunk/lib/Target/CppBackend/CPPBackend.cpp @@ -301,10 +301,6 @@ Out << "GlobalValue::AppendingLinkage"; break; case GlobalValue::ExternalLinkage: Out << "GlobalValue::ExternalLinkage"; break; - case GlobalValue::DLLImportLinkage: - Out << "GlobalValue::DLLImportLinkage"; break; - case GlobalValue::DLLExportLinkage: - Out << "GlobalValue::DLLExportLinkage"; break; case GlobalValue::ExternalWeakLinkage: Out << "GlobalValue::ExternalWeakLinkage"; break; case GlobalValue::CommonLinkage: @@ -510,6 +506,8 @@ HANDLE_ATTR(UWTable); HANDLE_ATTR(NonLazyBind); HANDLE_ATTR(MinSize); + HANDLE_ATTR(DLLExport); + HANDLE_ATTR(DLLImport); #undef HANDLE_ATTR if (attrs.contains(Attribute::StackAlignment)) { Index: llvm/trunk/lib/Target/Mangler.cpp =================================================================== --- llvm/trunk/lib/Target/Mangler.cpp +++ llvm/trunk/lib/Target/Mangler.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/Target/TargetMachine.h" @@ -237,6 +238,14 @@ MCSymbol *Mangler::getSymbol(const GlobalValue *GV) { SmallString<60> NameStr; getNameWithPrefix(NameStr, GV, false); + + if (const GlobalVariable *Var = dyn_cast(GV)) { + if (Var->hasDLLImportStorageClass()) { + const char *Prefix = "__imp_"; + NameStr.insert(NameStr.begin(), Prefix, Prefix+strlen(Prefix)); + } + } + return Context.GetOrCreateSymbol(NameStr.str()); } Index: llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp +++ llvm/trunk/lib/Target/X86/X86AsmPrinter.cpp @@ -644,14 +644,29 @@ static_cast(getObjFileLowering()); for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->hasDLLExportLinkage()) + if (I->hasFnAttribute(Attribute::DLLExport)) DLLExportedFns.push_back(Mang->getSymbol(I)); for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) - if (I->hasDLLExportLinkage()) + if (I->hasDLLExportStorageClass()) DLLExportedGlobals.push_back(Mang->getSymbol(I)); + for (Module::const_alias_iterator I = M.alias_begin(), E = M.alias_end(); + I != E; ++I) { + const GlobalValue *GV = I->getAliasedGlobal(); + while (const GlobalAlias *A = dyn_cast(GV)) + GV = A->getAliasedGlobal(); + + if (const Function *F = dyn_cast(GV)) { + if (F->hasFnAttribute(Attribute::DLLExport)) + DLLExportedFns.push_back(Mang->getSymbol(I)); + } else if (const GlobalVariable *V = dyn_cast(GV)) { + if (V->hasDLLExportStorageClass()) + DLLExportedGlobals.push_back(Mang->getSymbol(I)); + } + } + // Output linker support code for dllexported globals on windows. if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { OutStreamer.SwitchSection(TLOFCOFF.getDrectveSection()); Index: llvm/trunk/lib/Target/X86/X86FastISel.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86FastISel.cpp +++ llvm/trunk/lib/Target/X86/X86FastISel.cpp @@ -635,15 +635,21 @@ (AM.Base.Reg != 0 || AM.IndexReg != 0)) return false; - // Can't handle DLLImport. - if (GV->hasDLLImportLinkage()) - return false; - - // Can't handle TLS. - if (const GlobalVariable *GVar = dyn_cast(GV)) + if (const GlobalVariable *GVar = dyn_cast(GV)) { + // Can't handle TLS. if (GVar->isThreadLocal()) return false; + // Can't handle DLLImport. + if (GVar->hasDLLImportStorageClass()) + return false; + } + + if (const Function *F = dyn_cast(GV)) + // Can't handle DLLImport. + if (F->hasFnAttribute(Attribute::DLLImport)) + return false; + // Okay, we've committed to selecting this global. Set up the basic address. AM.GV = GV; Index: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp @@ -2271,6 +2271,16 @@ return Chain; } +static bool hasDLLImport(const GlobalValue *G) { + if (const GlobalVariable *GV = dyn_cast(G)) + return GV->hasDLLImportStorageClass(); + + if (const Function *F = dyn_cast(G)) + return F->hasFnAttribute(Attribute::DLLImport); + + return false; +} + SDValue X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { @@ -2567,7 +2577,7 @@ // We should use extra load for direct calls to dllimported functions in // non-JIT mode. const GlobalValue *GV = G->getGlobal(); - if (!GV->hasDLLImportLinkage()) { + if (!hasDLLImport(GV)) { unsigned char OpFlags = 0; bool ExtraLoad = false; unsigned WrapperKind = ISD::DELETED_NODE; Index: llvm/trunk/lib/Target/X86/X86Subtarget.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.cpp +++ llvm/trunk/lib/Target/X86/X86Subtarget.cpp @@ -17,6 +17,7 @@ #include "llvm/IR/Attributes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Host.h" @@ -48,6 +49,16 @@ return X86II::MO_NO_FLAG; } +static bool hasDLLImport(const GlobalValue *G) { + if (const GlobalVariable *GV = dyn_cast(G)) + return GV->hasDLLImportStorageClass(); + + if (const Function *F = dyn_cast(G)) + return F->hasFnAttribute(Attribute::DLLImport); + + return false; +} + /// ClassifyGlobalReference - Classify a global variable reference for the /// current subtarget according to how we should reference it in a non-pcrel /// context. @@ -55,7 +66,7 @@ ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const { // DLLImport only exists on windows, it is implemented as a load from a // DLLIMPORT stub. - if (GV->hasDLLImportLinkage()) + if (hasDLLImport(GV)) return X86II::MO_DLLIMPORT; // Determine whether this is a reference to a definition or a declaration. Index: llvm/trunk/lib/Target/XCore/XCoreAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/XCore/XCoreAsmPrinter.cpp +++ llvm/trunk/lib/Target/XCore/XCoreAsmPrinter.cpp @@ -133,10 +133,6 @@ case GlobalValue::InternalLinkage: case GlobalValue::PrivateLinkage: break; - case GlobalValue::DLLImportLinkage: - llvm_unreachable("DLLImport linkage is not supported by this target!"); - case GlobalValue::DLLExportLinkage: - llvm_unreachable("DLLExport linkage is not supported by this target!"); default: llvm_unreachable("Unknown linkage type!"); } Index: llvm/trunk/test/CodeGen/X86/dll-linkage.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/dll-linkage.ll +++ llvm/trunk/test/CodeGen/X86/dll-linkage.ll @@ -3,7 +3,7 @@ ; RUN: llc < %s -mtriple=i386-pc-mingw32 -O0 | FileCheck %s -check-prefix=FAST ; PR6275 -declare dllimport void @foo() +declare void @foo() dllimport define void @bar() nounwind { ; CHECK: calll *__imp__foo Index: llvm/trunk/test/CodeGen/X86/dllexport.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/dllexport.ll +++ llvm/trunk/test/CodeGen/X86/dllexport.ll @@ -3,7 +3,7 @@ target triple = "i386-pc-mingw32" -define dllexport x86_fastcallcc i32 @foo() nounwind { +define x86_fastcallcc i32 @foo() nounwind dllexport { entry: ret i32 0 } Index: llvm/trunk/test/MC/COFF/linker-options.ll =================================================================== --- llvm/trunk/test/MC/COFF/linker-options.ll +++ llvm/trunk/test/MC/COFF/linker-options.ll @@ -9,7 +9,7 @@ !llvm.module.flags = !{ !0 } -define dllexport void @foo() { +define void @foo() dllexport { ret void }