Index: include/clang/AST/DeclCXX.h =================================================================== --- include/clang/AST/DeclCXX.h +++ 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: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ 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: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1751,7 +1751,26 @@ 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_dllimpexp_c99_inline : Error< + "C99 inline functions cannot be %select{imported|exported}0">; +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 +1959,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: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ 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: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ 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,25 @@ 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"; + const DLLImportAttr *ImportAttr = FD->getAttr(); + const DLLExportAttr *ExportAttr = FD->getAttr(); + if (ImportAttr) { + // 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"; - } + if (getLangOpts().C99 && FD->isInlineSpecified() && + (ImportAttr || ExportAttr)) { + Diag(FD->getLocation(), diag::err_attribute_dllimpexp_c99_inline) + << (ExportAttr ? 1 : 0); + FD->setInvalidDecl(); } + // We want to attach documentation to original Decl (which might be // a function template). ActOnDocumentableDecl(D); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ 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: lib/Sema/TargetAttributesSema.cpp =================================================================== --- lib/Sema/TargetAttributesSema.cpp +++ 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: test/Rewriter/dllimport-typedef.c =================================================================== --- test/Rewriter/dllimport-typedef.c +++ 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: test/Rewriter/missing-dllimport.c =================================================================== --- test/Rewriter/missing-dllimport.c +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: not %clang_cc1 -triple i686-pc-win32 -fms-extensions -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-NEG %s -// RUN: not %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: test/Sema/dllexport.c =================================================================== --- /dev/null +++ test/Sema/dllexport.c @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %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() {} + +// Not allowed on C99 inline functions. +__declspec(dllexport) inline void inlineFunc() {} // expected-error{{C99 inline functions cannot be exported}} + +// 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}} + + +// 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: test/Sema/dllimport-dllexport.c =================================================================== --- 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: test/Sema/dllimport.c =================================================================== --- /dev/null +++ test/Sema/dllimport.c @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -triple i386-pc-win32 -fsyntax-only -verify %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}} + +// Not allowed on C99 inline functions. +__declspec(dllimport) inline void inlineFunc() {} // expected-error{{C99 inline functions cannot be imported}} + +// 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: test/SemaCXX/MicrosoftExtensions.cpp =================================================================== --- test/SemaCXX/MicrosoftExtensions.cpp +++ 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: test/SemaCXX/dllexport.cpp =================================================================== --- /dev/null +++ test/SemaCXX/dllexport.cpp @@ -0,0 +1,570 @@ +// 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 normalDecl(); + __declspec(dllexport) void normalDefined(); + __declspec(dllexport) void normalInside() {} + __declspec(dllexport) void normalInlineDef(); + __declspec(dllexport) inline void normalInlineDecl(); + __declspec(dllexport) virtual void virtualDecl(); + __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 staticDecl(); + __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 ignoredInside() {} + virtual void ignoredVirtual(); + virtual void ignoredVirtualInside() {} + 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 expInside() {} // 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 expVirtualInside() {} // 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 expStaticInside() {} // 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}} +}; + + +// 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(dllexport) void Redecls::normal() {} // expected-error{{'normal' redeclared with different DLL attributes}} +__declspec(dllexport) inline void Redecls::inlineDef() {} // expected-error{{'inlineDef' redeclared with different DLL attributes}} +__declspec(dllexport) void Redecls::inlineDecl() {} // expected-error{{'inlineDecl' redeclared with different DLL attributes}} + + + +// Class templates + +// Export whole class template. +template +struct __declspec(dllexport) ExportClassTmpl { + void publicNormalDefined(); + void publicNormalInside() {} + void publicNormalInlineDef(); + inline void publicNormalInlineDecl(); + 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 +}; + +template void ExportClassTmpl::publicNormalDefined() {} +template void ExportClassTmpl::publicVirtualDefined() {} +template void ExportClassTmpl::publicStaticDefined() {} +template inline void ExportClassTmpl::publicNormalInlineDef() {} +template inline void ExportClassTmpl::publicVirtualInlineDef() {} +template inline void ExportClassTmpl::publicStaticInlineDef() {} +template void ExportClassTmpl::publicNormalInlineDecl() {} +template void ExportClassTmpl::publicVirtualInlineDecl() {} +template void ExportClassTmpl::publicStaticInlineDecl() {} +template int ExportClassTmpl::publicStaticFieldDefined = 1; +template const int ExportClassTmpl::publicStaticConstFieldDefined = 1; + +template struct ExportClassTmpl; +template struct __declspec(dllexport) ExportClassTmpl; + + +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 +}; + +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(dllexport) ClassTmpl; + + +// Import individual members. +template +struct ExportMembersTmpl { + __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 staticField; + __declspec(dllexport) static int staticFieldDefined; + __declspec(dllexport) static const int staticConstField; + __declspec(dllexport) static const int staticConstFieldDefined; + __declspec(dllexport) static const int staticConstFieldInit = 1; +#if __has_feature(cxx_constexpr) + __declspec(dllexport) constexpr static int constexprField = 2; +#endif + + void ignoredNormal(); + void ignoredInside() {} + virtual void ignoredVirtual(); + virtual void ignoredVirtualInside() {} + static int ignoredStaticField; +}; + +template void ExportMembersTmpl::normalDefined() {} +template void ExportMembersTmpl::virtualDefined() {} +template void ExportMembersTmpl::staticDefined() {} +template inline void ExportMembersTmpl::normalInlineDef() {} +template inline void ExportMembersTmpl::virtualInlineDef() {} +template inline void ExportMembersTmpl::staticInlineDef() {} +template void ExportMembersTmpl::normalInlineDecl() {} +template void ExportMembersTmpl::virtualInlineDecl() {} +template void ExportMembersTmpl::staticInlineDecl() {} +template int ExportMembersTmpl::staticFieldDefined = 1; +template const int ExportMembersTmpl::staticConstFieldDefined = 1; + + +// If the whole class is exported, individual members cannot have an 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 expInside() {} // 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 expVirtualInside() {} // 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 expStaticInside() {} // 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}} +}; + + +// 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(dllexport) void RedeclsTmpl::normal() {} // expected-error{{'normal' redeclared with different DLL attributes}} + +template +__declspec(dllexport) inline void RedeclsTmpl::inlineDef() {} // expected-error{{'inlineDef' redeclared with different DLL attributes}} + +template +__declspec(dllexport) void RedeclsTmpl::inlineDecl() {} // expected-error{{'inlineDecl' redeclared with different DLL attributes}} + + + +// Warn about non-exported associated types, like base classes or field types. +struct __declspec(dllimport) Imported {}; +struct __declspec(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(); +}; + + +struct Base {}; + +template +struct BaseTmpl {}; + +struct __declspec(dllexport) ExportedBase {}; + +template +struct __declspec(dllexport) ExportedBaseTmpl {}; + +template +struct InstantiatedBase {}; + +template struct __declspec(dllexport) InstantiatedBase; + +struct __declspec(dllexport) Derived + : public Base, // expected-warning{{'Base' is a base of an exported type and should be exported}} + public BaseTmpl, // expected-warning{{'BaseTmpl' is a base of an exported type and should be exported}} + public ExportedBase, + public ExportedBaseTmpl, + public InstantiatedBase, + public InstantiatedBase { // expected-warning{{'InstantiatedBase' is a base of an exported type and should be exported}} +}; Index: test/SemaCXX/dllimport.cpp =================================================================== --- /dev/null +++ test/SemaCXX/dllimport.cpp @@ -0,0 +1,558 @@ +// 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 + +// 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}} + + + +struct Base {}; + +template +struct BaseTmpl {}; + +struct __declspec(dllimport) ImportedBase {}; + +template +struct __declspec(dllimport) ImportedBaseTmpl {}; + +template +struct InstantiatedBase {}; + +template struct __declspec(dllimport) InstantiatedBase; + +struct __declspec(dllimport) Derived + : public Base, + public BaseTmpl, + public ImportedBase, + public ImportedBaseTmpl, + public InstantiatedBase, + public InstantiatedBase { +}; Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ 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; }